PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/site-packages/wx-2.8-msw-unicode/wx/lib/agw/aui/aui_utilities.py

https://github.com/astory/RankPanda
Python | 468 lines | 279 code | 58 blank | 131 comment | 19 complexity | 5750314592400efc67bca6e31e06a5d7 MD5 | raw file
  1. """
  2. This module contains some common functions used by wxPython-AUI to
  3. manipulate colours, bitmaps, text, gradient shadings and custom
  4. dragging images for AuiNotebook tabs.
  5. """
  6. __author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
  7. __date__ = "31 March 2009"
  8. import wx
  9. from aui_constants import AUI_BUTTON_STATE_PRESSED, AUI_GRADIENT_VERTICAL
  10. from aui_constants import AUI_BUTTON_STATE_HIDDEN
  11. if wx.Platform == "__WXMAC__":
  12. import Carbon.Appearance
  13. def BlendColour(fg, bg, alpha):
  14. """
  15. Blends the two colour component `fg` and `bg` into one colour component, adding
  16. an optional alpha channel.
  17. :param `fg`: the first colour component;
  18. :param `bg`: the second colour component;
  19. :param `alpha`: an optional transparency value.
  20. """
  21. result = bg + (alpha*(fg - bg))
  22. if result < 0.0:
  23. result = 0.0
  24. if result > 255:
  25. result = 255
  26. return result
  27. def StepColour(c, ialpha):
  28. """
  29. Darken/lighten the input colour `c`.
  30. :param `c`: a colour to darken/lighten;
  31. :param `ialpha`: a transparency value.
  32. """
  33. if ialpha == 100:
  34. return c
  35. r, g, b = c.Red(), c.Green(), c.Blue()
  36. # ialpha is 0..200 where 0 is completely black
  37. # and 200 is completely white and 100 is the same
  38. # convert that to normal alpha 0.0 - 1.0
  39. ialpha = min(ialpha, 200)
  40. ialpha = max(ialpha, 0)
  41. alpha = (ialpha - 100.0)/100.0
  42. if ialpha > 100:
  43. # blend with white
  44. bg = 255
  45. alpha = 1.0 - alpha # 0 = transparent fg 1 = opaque fg
  46. else:
  47. # blend with black
  48. bg = 0
  49. alpha = 1.0 + alpha # 0 = transparent fg 1 = opaque fg
  50. r = BlendColour(r, bg, alpha)
  51. g = BlendColour(g, bg, alpha)
  52. b = BlendColour(b, bg, alpha)
  53. return wx.Colour(r, g, b)
  54. def LightContrastColour(c):
  55. """
  56. Creates a new, lighter colour based on the input colour `c`.
  57. :param `c`: the input colour to analyze.
  58. """
  59. amount = 120
  60. # if the color is especially dark, then
  61. # make the contrast even lighter
  62. if c.Red() < 128 and c.Green() < 128 and c.Blue() < 128:
  63. amount = 160
  64. return StepColour(c, amount)
  65. def ChopText(dc, text, max_size):
  66. """
  67. Chops the input `text` if its size does not fit in `max_size`, by cutting the
  68. text and adding ellipsis at the end.
  69. :param `dc`: a wx.DC device context;
  70. :param `text`: the text to chop;
  71. :param `max_size`: the maximum size in which the text should fit.
  72. """
  73. # first check if the text fits with no problems
  74. x, y = dc.GetTextExtent(text)
  75. if x <= max_size:
  76. return text
  77. textLen = len(text)
  78. last_good_length = 0
  79. for i in xrange(textLen, -1, -1):
  80. s = text[0:i]
  81. s += "..."
  82. x, y = dc.GetTextExtent(s)
  83. last_good_length = i
  84. if x < max_size:
  85. break
  86. ret = text[0:last_good_length] + "..."
  87. return ret
  88. def BitmapFromBits(bits, w, h, color):
  89. """
  90. BitmapFromBits() is a utility function that creates a
  91. masked bitmap from raw bits (XBM format).
  92. :param `bits`: a string containing the raw bits of the bitmap;
  93. :param `w`: the bitmap width;
  94. :param `h`: the bitmap height;
  95. :param `colour`: the colour which will replace all white pixels in the
  96. raw bitmap.
  97. """
  98. img = wx.BitmapFromBits(bits, w, h).ConvertToImage()
  99. img.Replace(0, 0, 0, 123, 123, 123)
  100. img.Replace(255, 255, 255, color.Red(), color.Green(), color.Blue())
  101. img.SetMaskColour(123, 123, 123)
  102. return wx.BitmapFromImage(img)
  103. def IndentPressedBitmap(rect, button_state):
  104. """
  105. Indents the input rectangle `rect` based on the value of `button_state`.
  106. :param `rect`: an instance of wx.Rect;
  107. :param `button_state`: an AuiNotebook button state.
  108. """
  109. if button_state == AUI_BUTTON_STATE_PRESSED:
  110. rect.x += 1
  111. rect.y += 1
  112. return rect
  113. def GetBaseColour():
  114. """ Returns the face shading colour on push buttons/backgrounds. """
  115. if wx.Platform == "__WXMAC__":
  116. if hasattr(wx, 'MacThemeColour'):
  117. base_colour = wx.MacThemeColour(Carbon.Appearance.kThemeBrushToolbarBackground)
  118. else:
  119. brush = wx.Brush(wx.BLACK)
  120. brush.MacSetTheme(Carbon.Appearance.kThemeBrushToolbarBackground)
  121. base_colour = brush.GetColour()
  122. else:
  123. base_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)
  124. # the base_colour is too pale to use as our base colour,
  125. # so darken it a bit
  126. if ((255-base_colour.Red()) +
  127. (255-base_colour.Green()) +
  128. (255-base_colour.Blue()) < 60):
  129. base_colour = StepColour(base_colour, 92)
  130. return base_colour
  131. def MakeDisabledBitmap(bitmap):
  132. """
  133. Convert the given image (in place) to a grayed-out version,
  134. appropriate for a 'disabled' appearance.
  135. :param: `bitmap`: the bitmap to gray-out.
  136. """
  137. anImage = bitmap.ConvertToImage()
  138. factor = 0.7 # 0 < f < 1. Higher Is Grayer
  139. if anImage.HasMask():
  140. maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
  141. else:
  142. maskColor = None
  143. data = map(ord, list(anImage.GetData()))
  144. for i in range(0, len(data), 3):
  145. pixel = (data[i], data[i+1], data[i+2])
  146. pixel = MakeGray(pixel, factor, maskColor)
  147. for x in range(3):
  148. data[i+x] = pixel[x]
  149. anImage.SetData(''.join(map(chr, data)))
  150. return anImage.ConvertToBitmap()
  151. def MakeGray((r,g,b), factor, maskColor):
  152. """
  153. Make a pixel grayed-out. If the pixel matches the `maskColor`, it won't be
  154. changed.
  155. :param `(r,g,b)`: a tuple representing a pixel colour;
  156. :param `factor`: a graying-out factor;
  157. :param `maskColor`: a colour mask.
  158. """
  159. if (r,g,b) != maskColor:
  160. return map(lambda x: int((230 - x) * factor) + x, (r,g,b))
  161. else:
  162. return (r,g,b)
  163. def Clip(a, b, c):
  164. """
  165. Clips the value in `a` based on the extremes `b` and `c`.
  166. :param `a`: the value to analyze;
  167. :param `b`: a minimum value;
  168. :param `c`: a maximum value.
  169. """
  170. return ((a < b and [b]) or [(a > c and [c] or [a])[0]])[0]
  171. def LightColour(color, percent):
  172. """
  173. Brighten input colour by `percent`.
  174. :param `colour`: the colour to be brightened;
  175. :param `percent`: brightening percentage.
  176. """
  177. end_color = wx.WHITE
  178. rd = end_color.Red() - color.Red()
  179. gd = end_color.Green() - color.Green()
  180. bd = end_color.Blue() - color.Blue()
  181. high = 100
  182. # We take the percent way of the color from color -. white
  183. i = percent
  184. r = color.Red() + ((i*rd*100)/high)/100
  185. g = color.Green() + ((i*gd*100)/high)/100
  186. b = color.Blue() + ((i*bd*100)/high)/100
  187. return wx.Colour(r, g, b)
  188. def PaneCreateStippleBitmap():
  189. """
  190. Creates a stipple bitmap to be used in a wx.Brush.
  191. This is used to draw sash resize hints.
  192. """
  193. data = [0, 0, 0, 192, 192, 192, 192, 192, 192, 0, 0, 0]
  194. img = wx.EmptyImage(2, 2)
  195. counter = 0
  196. for ii in xrange(2):
  197. for jj in xrange(2):
  198. img.SetRGB(ii, jj, data[counter], data[counter+1], data[counter+2])
  199. counter = counter + 3
  200. return img.ConvertToBitmap()
  201. def DrawMACCloseButton(colour, backColour=None):
  202. """
  203. Draws the wxMAC tab close button using wx.GraphicsContext.
  204. :param `colour`: the colour to use to draw the circle.
  205. """
  206. bmp = wx.EmptyBitmapRGBA(16, 16)
  207. dc = wx.MemoryDC()
  208. dc.SelectObject(bmp)
  209. gc = wx.GraphicsContext.Create(dc)
  210. gc.SetBrush(wx.Brush(colour))
  211. path = gc.CreatePath()
  212. path.AddCircle(6.5, 7, 6.5)
  213. path.CloseSubpath()
  214. gc.FillPath(path)
  215. path = gc.CreatePath()
  216. if backColour is not None:
  217. pen = wx.Pen(backColour, 2)
  218. else:
  219. pen = wx.Pen("white", 2)
  220. pen.SetCap(wx.CAP_BUTT)
  221. pen.SetJoin(wx.JOIN_BEVEL)
  222. gc.SetPen(pen)
  223. path.MoveToPoint(3.5, 4)
  224. path.AddLineToPoint(9.5, 10)
  225. path.MoveToPoint(3.5, 10)
  226. path.AddLineToPoint(9.5, 4)
  227. path.CloseSubpath()
  228. gc.DrawPath(path)
  229. dc.SelectObject(wx.NullBitmap)
  230. return bmp
  231. def DarkenBitmap(bmp, caption_colour, new_colour):
  232. """
  233. Darkens the input bitmap on wxMAC using the input colour.
  234. :param `bmp`: the bitmap to be manipulated;
  235. :param `caption_colour`: the colour of the pane caption
  236. :param `new_colour`: the colour used to darken the bitmap.
  237. """
  238. image = bmp.ConvertToImage()
  239. red = caption_colour.Red()/float(new_colour.Red())
  240. green = caption_colour.Green()/float(new_colour.Green())
  241. blue = caption_colour.Blue()/float(new_colour.Blue())
  242. image = image.AdjustChannels(red, green, blue)
  243. return image.ConvertToBitmap()
  244. def DrawGradientRectangle(dc, rect, start_colour, end_colour, direction, offset=0, length=0):
  245. """
  246. Draws a gradient-shaded rectangle.
  247. :param `dc`: a wx.DC device context;
  248. :param `rect`: the rectangle in which to draw the gradient;
  249. :param `start_colour`: the first colour of the gradient;
  250. :param `end_colour`: the second colour of the gradient;
  251. :param `direction`: the gradient direction (horizontal or vertical).
  252. """
  253. if direction == AUI_GRADIENT_VERTICAL:
  254. dc.GradientFillLinear(rect, start_colour, end_colour, wx.SOUTH)
  255. else:
  256. dc.GradientFillLinear(rect, start_colour, end_colour, wx.EAST)
  257. def FindFocusDescendant(ancestor):
  258. """
  259. Find a window with the focus, that is also a descendant of the given window.
  260. This is used to determine the window to initially send commands to.
  261. :param `ancestor`: the window to check for ancestry.
  262. """
  263. # Process events starting with the window with the focus, if any.
  264. focusWin = wx.Window.FindFocus()
  265. win = focusWin
  266. # Check if this is a descendant of this frame.
  267. # If not, win will be set to NULL.
  268. while win:
  269. if win == ancestor:
  270. break
  271. else:
  272. win = win.GetParent()
  273. if win is None:
  274. focusWin = None
  275. return focusWin
  276. #---------------------------------------------------------------------------
  277. # TabDragImage implementation
  278. # This class handles the creation of a custom image when dragging
  279. # AuiNotebook tabs
  280. #---------------------------------------------------------------------------
  281. class TabDragImage(wx.DragImage):
  282. """
  283. This class handles the creation of a custom image in case of drag and
  284. drop of a notebook tab.
  285. """
  286. def __init__(self, notebook, page, button_state, tabArt):
  287. """
  288. Default class constructor.
  289. For internal use: do not call it in your code!
  290. :param `notebook`: an instance of L{auibook.AuiNotebook};
  291. :param `page`: the dragged AuiNotebook page;
  292. :param `button_state`: the state of the close button on the tab;
  293. :param `tabArt`: an instance of L{tabart}.
  294. """
  295. self._backgroundColour = wx.NamedColour("pink")
  296. self._bitmap = self.CreateBitmap(notebook, page, button_state, tabArt)
  297. wx.DragImage.__init__(self, self._bitmap)
  298. def CreateBitmap(self, notebook, page, button_state, tabArt):
  299. """
  300. Actually creates the dnd bitmap.
  301. :param `notebook`: an instance of L{auibook.AuiNotebook};
  302. :param `page`: the dragged AuiNotebook page;
  303. :param `button_state`: the state of the close button on the tab;
  304. :param `tabArt`: an instance of L{tabart}.
  305. """
  306. memory = wx.MemoryDC(wx.EmptyBitmap(1, 1))
  307. tab_size, x_extent = tabArt.GetTabSize(memory, notebook, page.caption, page.bitmap, page.active,
  308. button_state)
  309. tab_width, tab_height = tab_size
  310. rect = wx.Rect(0, 0, tab_width, tab_height)
  311. bitmap = wx.EmptyBitmap(tab_width+1, tab_height+1)
  312. memory.SelectObject(bitmap)
  313. if wx.Platform == "__WXMAC__":
  314. memory.SetBackground(wx.TRANSPARENT_BRUSH)
  315. else:
  316. memory.SetBackground(wx.Brush(self._backgroundColour))
  317. memory.SetBackgroundMode(wx.TRANSPARENT)
  318. memory.Clear()
  319. tabArt.DrawTab(memory, notebook, page, rect, button_state)
  320. memory.SetBrush(wx.TRANSPARENT_BRUSH)
  321. memory.SetPen(wx.BLACK_PEN)
  322. memory.DrawRoundedRectangle(0, 0, tab_width+1, tab_height+1, 2)
  323. memory.SelectObject(wx.NullBitmap)
  324. # Gtk and Windows unfortunatly don't do so well with transparent
  325. # drawing so this hack corrects the image to have a transparent
  326. # background.
  327. if wx.Platform != '__WXMAC__':
  328. timg = bitmap.ConvertToImage()
  329. if not timg.HasAlpha():
  330. timg.InitAlpha()
  331. for y in xrange(timg.GetHeight()):
  332. for x in xrange(timg.GetWidth()):
  333. pix = wx.Colour(timg.GetRed(x, y),
  334. timg.GetGreen(x, y),
  335. timg.GetBlue(x, y))
  336. if pix == self._backgroundColour:
  337. timg.SetAlpha(x, y, 0)
  338. bitmap = timg.ConvertToBitmap()
  339. return bitmap