2
This module contains drawing routines and customizations for the AGW widgets
3
:class:`~lib.agw.labelbook.LabelBook` and :class:`~lib.agw.flatmenu.FlatMenu`.
10
from fmresources import *
12
# ---------------------------------------------------------------------------- #
14
# ---------------------------------------------------------------------------- #
20
if wx.Platform == "__WXMSW__":
21
osVersion = wx.GetOsVersion()
22
# Shadows behind menus are supported only in XP
23
if osVersion[1] == 5 and osVersion[2] == 1:
32
_libimported = "ctypes"
39
class DCSaver(object):
41
Construct a DC saver. The dc is copied as-is.
44
def __init__(self, pdc):
46
Default class constructor.
48
:param `pdc`: an instance of :class:`DC`.
52
self._pen = pdc.GetPen()
53
self._brush = pdc.GetBrush()
57
""" While destructing, restores the dc pen and brush. """
60
self._pdc.SetPen(self._pen)
61
self._pdc.SetBrush(self._brush)
64
# ---------------------------------------------------------------------------- #
66
# ---------------------------------------------------------------------------- #
68
class RendererBase(object):
69
""" Base class for all theme renderers. """
72
""" Default class constructor. Intentionally empty. """
77
def DrawButtonBorders(self, dc, rect, penColour, brushColour):
79
Draws borders for buttons.
81
:param `dc`: an instance of :class:`DC`;
82
:param Rect `rect`: the button's client rectangle;
83
:param `penColour`: a valid :class:`Colour` for the pen border;
84
:param `brushColour`: a valid :class:`Colour` for the brush.
87
# Keep old pen and brush
89
dc.SetPen(wx.Pen(penColour))
90
dc.SetBrush(wx.Brush(brushColour))
91
dc.DrawRectangleRect(rect)
94
def DrawBitmapArea(self, dc, xpm_name, rect, baseColour, flipSide):
96
Draws the area below a bitmap and the bitmap itself using a gradient shading.
98
:param `dc`: an instance of :class:`DC`;
99
:param string `xpm_name`: a name of a XPM bitmap;
100
:param Rect `rect`: the bitmap client rectangle;
101
:param `baseColour`: a valid :class:`Colour` for the bitmap background;
102
:param bool `flipSide`: ``True`` to flip the gradient direction, ``False`` otherwise.
105
# draw the gradient area
107
ArtManager.Get().PaintDiagonalGradientBox(dc, rect, wx.WHITE,
108
ArtManager.Get().LightColour(baseColour, 20),
111
ArtManager.Get().PaintDiagonalGradientBox(dc, rect, ArtManager.Get().LightColour(baseColour, 20),
112
wx.WHITE, True, False)
115
arrowDown = wx.BitmapFromXPMData(xpm_name)
116
arrowDown.SetMask(wx.Mask(arrowDown, wx.WHITE))
117
dc.DrawBitmap(arrowDown, rect.x + 1 , rect.y + 1, True)
120
def DrawBitmapBorders(self, dc, rect, penColour, bitmapBorderUpperLeftPen):
122
Draws borders for a bitmap.
124
:param `dc`: an instance of :class:`DC`;
125
:param Rect `rect`: the button's client rectangle;
126
:param `penColour`: a valid :class:`Colour` for the pen border;
127
:param `bitmapBorderUpperLeftPen`: a valid :class:`Colour` for the pen upper
131
# Keep old pen and brush
132
dcsaver = DCSaver(dc)
135
dc.SetPen(wx.Pen(penColour))
136
dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1)
137
dc.DrawLine(rect.x + rect.width - 1, rect.y, rect.x + rect.width - 1, rect.y + rect.height)
140
dc.SetPen(wx.Pen(bitmapBorderUpperLeftPen))
141
dc.DrawLine(rect.x, rect.y, rect.x + rect.width, rect.y)
142
dc.DrawLine(rect.x, rect.y, rect.x, rect.y + rect.height)
145
def GetMenuFaceColour(self):
147
Returns the foreground colour for the menu.
149
:return: An instance of :class:`Colour`.
152
return ArtManager.Get().LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 80)
155
def GetTextColourEnable(self):
157
Returns the colour used for text colour when enabled.
159
:return: An instance of :class:`Colour`.
165
def GetTextColourDisable(self):
167
Returns the colour used for text colour when disabled.
169
:return: An instance of :class:`Colour`.
172
return ArtManager.Get().LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT), 30)
177
Returns the font used for text.
179
:return: An instance of :class:`Font`.
182
return wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
185
# ---------------------------------------------------------------------------- #
187
# ---------------------------------------------------------------------------- #
189
class RendererXP(RendererBase):
190
""" Xp-Style renderer. """
193
""" Default class constructor. """
195
RendererBase.__init__(self)
198
def DrawButton(self, dc, rect, state, input=None):
200
Draws a button using the XP theme.
202
:param `dc`: an instance of :class:`DC`;
203
:param Rect `rect`: the button's client rectangle;
204
:param integer `state`: the button state;
205
:param `input`: a flag used to call the right method.
208
if input is None or type(input) == type(False):
209
self.DrawButtonTheme(dc, rect, state, input)
211
self.DrawButtonColour(dc, rect, state, input)
214
def DrawButtonTheme(self, dc, rect, state, useLightColours=None):
216
Draws a button using the XP theme.
218
:param `dc`: an instance of :class:`DC`;
219
:param Rect `rect`: the button's client rectangle;
220
:param integer `state`: the button state;
221
:param bool `useLightColours`: ``True`` to use light colours, ``False`` otherwise.
224
# switch according to the status
225
if state == ControlFocus:
226
penColour = ArtManager.Get().FrameColour()
227
brushColour = ArtManager.Get().BackgroundColour()
228
elif state == ControlPressed:
229
penColour = ArtManager.Get().FrameColour()
230
brushColour = ArtManager.Get().HighlightBackgroundColour()
232
penColour = ArtManager.Get().FrameColour()
233
brushColour = ArtManager.Get().BackgroundColour()
235
# Draw the button borders
236
self.DrawButtonBorders(dc, rect, penColour, brushColour)
239
def DrawButtonColour(self, dc, rect, state, colour):
241
Draws a button using the XP theme.
243
:param `dc`: an instance of :class:`DC`;
244
:param Rect `rect`: the button's client rectangle;
245
:param integer `state`: the button state;
246
:param `colour`: a valid :class:`Colour` instance.
249
# switch according to the status
250
if statet == ControlFocus:
252
brushColour = ArtManager.Get().LightColour(colour, 75)
253
elif state == ControlPressed:
255
brushColour = ArtManager.Get().LightColour(colour, 60)
258
brushColour = ArtManager.Get().LightColour(colour, 75)
260
# Draw the button borders
261
self.DrawButtonBorders(dc, rect, penColour, brushColour)
264
def DrawMenuBarBg(self, dc, rect):
266
Draws the menu bar background according to the active theme.
268
:param `dc`: an instance of :class:`DC`;
269
:param Rect `rect`: the menu bar's client rectangle.
272
# For office style, we simple draw a rectangle with a gradient colouring
273
artMgr = ArtManager.Get()
274
vertical = artMgr.GetMBVerticalGradient()
276
dcsaver = DCSaver(dc)
279
startColour = artMgr.GetMenuBarFaceColour()
280
if artMgr.IsDark(startColour):
281
startColour = artMgr.LightColour(startColour, 50)
283
endColour = artMgr.LightColour(startColour, 90)
284
artMgr.PaintStraightGradientBox(dc, rect, startColour, endColour, vertical)
287
if artMgr.GetMenuBarBorder():
289
dc.SetPen(wx.Pen(startColour))
290
dc.SetBrush(wx.TRANSPARENT_BRUSH)
291
dc.DrawRectangleRect(rect)
294
def DrawToolBarBg(self, dc, rect):
296
Draws the toolbar background according to the active theme.
298
:param `dc`: an instance of :class:`DC`;
299
:param Rect `rect`: the toolbar's client rectangle.
302
artMgr = ArtManager.Get()
304
if not artMgr.GetRaiseToolbar():
307
# For office style, we simple draw a rectangle with a gradient colouring
308
vertical = artMgr.GetMBVerticalGradient()
310
dcsaver = DCSaver(dc)
313
startColour = artMgr.GetMenuBarFaceColour()
314
if artMgr.IsDark(startColour):
315
startColour = artMgr.LightColour(startColour, 50)
317
startColour = artMgr.LightColour(startColour, 20)
319
endColour = artMgr.LightColour(startColour, 90)
320
artMgr.PaintStraightGradientBox(dc, rect, startColour, endColour, vertical)
321
artMgr.DrawBitmapShadow(dc, rect)
324
def GetTextColourEnable(self):
326
Returns the colour used for text colour when enabled.
328
:return: An instance of :class:`Colour`.
334
# ---------------------------------------------------------------------------- #
335
# Class RendererMSOffice2007
336
# ---------------------------------------------------------------------------- #
338
class RendererMSOffice2007(RendererBase):
339
""" Windows MS Office 2007 style. """
342
""" Default class constructor. """
344
RendererBase.__init__(self)
347
def GetColoursAccordingToState(self, state):
349
Returns a :class:`Colour` according to the menu item state.
351
:param integer `state`: one of the following bits:
353
==================== ======= ==========================
354
Item State Value Description
355
==================== ======= ==========================
356
``ControlPressed`` 0 The item is pressed
357
``ControlFocus`` 1 The item is focused
358
``ControlDisabled`` 2 The item is disabled
359
``ControlNormal`` 3 Normal state
360
==================== ======= ==========================
362
:return: An instance of :class:`Colour`.
365
# switch according to the status
366
if state == ControlFocus:
367
upperBoxTopPercent = 95
368
upperBoxBottomPercent = 50
369
lowerBoxTopPercent = 40
370
lowerBoxBottomPercent = 90
371
concaveUpperBox = True
372
concaveLowerBox = True
374
elif state == ControlPressed:
375
upperBoxTopPercent = 75
376
upperBoxBottomPercent = 90
377
lowerBoxTopPercent = 90
378
lowerBoxBottomPercent = 40
379
concaveUpperBox = True
380
concaveLowerBox = True
382
elif state == ControlDisabled:
383
upperBoxTopPercent = 100
384
upperBoxBottomPercent = 100
385
lowerBoxTopPercent = 70
386
lowerBoxBottomPercent = 70
387
concaveUpperBox = True
388
concaveLowerBox = True
391
upperBoxTopPercent = 90
392
upperBoxBottomPercent = 50
393
lowerBoxTopPercent = 30
394
lowerBoxBottomPercent = 75
395
concaveUpperBox = True
396
concaveLowerBox = True
398
return upperBoxTopPercent, upperBoxBottomPercent, lowerBoxTopPercent, lowerBoxBottomPercent, \
399
concaveUpperBox, concaveLowerBox
402
def DrawButton(self, dc, rect, state, useLightColours):
404
Draws a button using the MS Office 2007 theme.
406
:param `dc`: an instance of :class:`DC`;
407
:param Rect `rect`: the button's client rectangle;
408
:param integer `state`: the button state;
409
:param bool `useLightColours`: ``True`` to use light colours, ``False`` otherwise.
412
self.DrawButtonColour(dc, rect, state, ArtManager.Get().GetThemeBaseColour(useLightColours))
415
def DrawButtonColour(self, dc, rect, state, colour):
417
Draws a button using the MS Office 2007 theme.
419
:param `dc`: an instance of :class:`DC`;
420
:param Rect `rect`: the button's client rectangle;
421
:param integer `state`: the button state;
422
:param `colour`: a valid :class:`Colour` instance.
425
artMgr = ArtManager.Get()
427
# Keep old pen and brush
428
dcsaver = DCSaver(dc)
430
# Define the rounded rectangle base on the given rect
431
# we need an array of 9 points for it
434
# Define the middle points
435
leftPt = wx.Point(rect.x, rect.y + (rect.height / 2))
436
rightPt = wx.Point(rect.x + rect.width-1, rect.y + (rect.height / 2))
438
# Define the top region
439
top = wx.RectPP((rect.GetLeft(), rect.GetTop()), rightPt)
440
bottom = wx.RectPP(leftPt, (rect.GetRight(), rect.GetBottom()))
442
upperBoxTopPercent, upperBoxBottomPercent, lowerBoxTopPercent, lowerBoxBottomPercent, \
443
concaveUpperBox, concaveLowerBox = self.GetColoursAccordingToState(state)
445
topStartColour = artMgr.LightColour(baseColour, upperBoxTopPercent)
446
topEndColour = artMgr.LightColour(baseColour, upperBoxBottomPercent)
447
bottomStartColour = artMgr.LightColour(baseColour, lowerBoxTopPercent)
448
bottomEndColour = artMgr.LightColour(baseColour, lowerBoxBottomPercent)
450
artMgr.PaintStraightGradientBox(dc, top, topStartColour, topEndColour)
451
artMgr.PaintStraightGradientBox(dc, bottom, bottomStartColour, bottomEndColour)
453
rr = wx.Rect(rect.x, rect.y, rect.width, rect.height)
454
dc.SetBrush(wx.TRANSPARENT_BRUSH)
456
frameColour = artMgr.LightColour(baseColour, 60)
457
dc.SetPen(wx.Pen(frameColour))
458
dc.DrawRectangleRect(rr)
460
wc = artMgr.LightColour(baseColour, 80)
461
dc.SetPen(wx.Pen(wc))
463
dc.DrawRectangleRect(rr)
466
def DrawMenuBarBg(self, dc, rect):
468
Draws the menu bar background according to the active theme.
470
:param `dc`: an instance of :class:`DC`;
471
:param Rect `rect`: the menu bar's client rectangle.
474
# Keep old pen and brush
475
dcsaver = DCSaver(dc)
476
artMgr = ArtManager.Get()
477
baseColour = artMgr.GetMenuBarFaceColour()
479
dc.SetBrush(wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
480
dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
481
dc.DrawRectangleRect(rect)
483
# Define the rounded rectangle base on the given rect
484
# we need an array of 9 points for it
485
regPts = [wx.Point() for ii in xrange(9)]
488
regPts[0] = wx.Point(rect.x, rect.y + radius)
489
regPts[1] = wx.Point(rect.x+radius, rect.y)
490
regPts[2] = wx.Point(rect.x+rect.width-radius-1, rect.y)
491
regPts[3] = wx.Point(rect.x+rect.width-1, rect.y + radius)
492
regPts[4] = wx.Point(rect.x+rect.width-1, rect.y + rect.height - radius - 1)
493
regPts[5] = wx.Point(rect.x+rect.width-radius-1, rect.y + rect.height-1)
494
regPts[6] = wx.Point(rect.x+radius, rect.y + rect.height-1)
495
regPts[7] = wx.Point(rect.x, rect.y + rect.height - radius - 1)
496
regPts[8] = regPts[0]
498
# Define the middle points
500
factor = artMgr.GetMenuBgFactor()
502
leftPt1 = wx.Point(rect.x, rect.y + (rect.height / factor))
503
leftPt2 = wx.Point(rect.x, rect.y + (rect.height / factor)*(factor-1))
505
rightPt1 = wx.Point(rect.x + rect.width, rect.y + (rect.height / factor))
506
rightPt2 = wx.Point(rect.x + rect.width, rect.y + (rect.height / factor)*(factor-1))
508
# Define the top region
509
topReg = [wx.Point() for ii in xrange(7)]
510
topReg[0] = regPts[0]
511
topReg[1] = regPts[1]
512
topReg[2] = wx.Point(regPts[2].x+1, regPts[2].y)
513
topReg[3] = wx.Point(regPts[3].x + 1, regPts[3].y)
514
topReg[4] = wx.Point(rightPt1.x, rightPt1.y+1)
515
topReg[5] = wx.Point(leftPt1.x, leftPt1.y+1)
516
topReg[6] = topReg[0]
518
# Define the middle region
519
middle = wx.RectPP(leftPt1, wx.Point(rightPt2.x - 2, rightPt2.y))
521
# Define the bottom region
522
bottom = wx.RectPP(leftPt2, wx.Point(rect.GetRight() - 1, rect.GetBottom()))
524
topStartColour = artMgr.LightColour(baseColour, 90)
525
topEndColour = artMgr.LightColour(baseColour, 60)
526
bottomStartColour = artMgr.LightColour(baseColour, 40)
527
bottomEndColour = artMgr.LightColour(baseColour, 20)
529
topRegion = wx.RegionFromPoints(topReg)
531
artMgr.PaintGradientRegion(dc, topRegion, topStartColour, topEndColour)
532
artMgr.PaintStraightGradientBox(dc, bottom, bottomStartColour, bottomEndColour)
533
artMgr.PaintStraightGradientBox(dc, middle, topEndColour, bottomStartColour)
536
def DrawToolBarBg(self, dc, rect):
538
Draws the toolbar background according to the active theme.
540
:param `dc`: an instance of :class:`DC`;
541
:param Rect `rect`: the toolbar's client rectangle.
544
artMgr = ArtManager.Get()
546
if not artMgr.GetRaiseToolbar():
549
# Keep old pen and brush
550
dcsaver = DCSaver(dc)
552
baseColour = artMgr.GetMenuBarFaceColour()
553
baseColour = artMgr.LightColour(baseColour, 20)
555
dc.SetBrush(wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
556
dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
557
dc.DrawRectangleRect(rect)
561
# Define the rounded rectangle base on the given rect
562
# we need an array of 9 points for it
565
regPts[0] = wx.Point(rect.x, rect.y + radius)
566
regPts[1] = wx.Point(rect.x+radius, rect.y)
567
regPts[2] = wx.Point(rect.x+rect.width-radius-1, rect.y)
568
regPts[3] = wx.Point(rect.x+rect.width-1, rect.y + radius)
569
regPts[4] = wx.Point(rect.x+rect.width-1, rect.y + rect.height - radius - 1)
570
regPts[5] = wx.Point(rect.x+rect.width-radius-1, rect.y + rect.height-1)
571
regPts[6] = wx.Point(rect.x+radius, rect.y + rect.height-1)
572
regPts[7] = wx.Point(rect.x, rect.y + rect.height - radius - 1)
573
regPts[8] = regPts[0]
575
# Define the middle points
576
factor = artMgr.GetMenuBgFactor()
578
leftPt1 = wx.Point(rect.x, rect.y + (rect.height / factor))
579
rightPt1 = wx.Point(rect.x + rect.width, rect.y + (rect.height / factor))
581
leftPt2 = wx.Point(rect.x, rect.y + (rect.height / factor)*(factor-1))
582
rightPt2 = wx.Point(rect.x + rect.width, rect.y + (rect.height / factor)*(factor-1))
584
# Define the top region
586
topReg[0] = regPts[0]
587
topReg[1] = regPts[1]
588
topReg[2] = wx.Point(regPts[2].x+1, regPts[2].y)
589
topReg[3] = wx.Point(regPts[3].x + 1, regPts[3].y)
590
topReg[4] = wx.Point(rightPt1.x, rightPt1.y+1)
591
topReg[5] = wx.Point(leftPt1.x, leftPt1.y+1)
592
topReg[6] = topReg[0]
594
# Define the middle region
595
middle = wx.RectPP(leftPt1, wx.Point(rightPt2.x - 2, rightPt2.y))
597
# Define the bottom region
598
bottom = wx.RectPP(leftPt2, wx.Point(rect.GetRight() - 1, rect.GetBottom()))
600
topStartColour = artMgr.LightColour(baseColour, 90)
601
topEndColour = artMgr.LightColour(baseColour, 60)
602
bottomStartColour = artMgr.LightColour(baseColour, 40)
603
bottomEndColour = artMgr.LightColour(baseColour, 20)
605
topRegion = wx.RegionFromPoints(topReg)
607
artMgr.PaintGradientRegion(dc, topRegion, topStartColour, topEndColour)
608
artMgr.PaintStraightGradientBox(dc, bottom, bottomStartColour, bottomEndColour)
609
artMgr.PaintStraightGradientBox(dc, middle, topEndColour, bottomStartColour)
611
artMgr.DrawBitmapShadow(dc, rect)
614
def GetTextColourEnable(self):
616
Returns the colour used for text colour when enabled.
618
:return: An instance of :class:`Colour`.
621
return wx.NamedColour("MIDNIGHT BLUE")
624
# ---------------------------------------------------------------------------- #
626
# ---------------------------------------------------------------------------- #
628
class ArtManager(wx.EvtHandler):
631
This class provides various art utilities, such as creating shadow, providing
632
lighter / darker colours for a given colour, etc...
637
_verticalGradient = False
638
_renderers = {StyleXP: None, Style2007: None}
639
_bmpShadowEnabled = False
640
_ms2007sunken = False
643
_menuBarColourScheme = _("Default")
649
""" Default class constructor. """
651
wx.EvtHandler.__init__(self)
652
self._menuBarBgColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
654
# connect an event handler to the system colour change event
655
self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChange)
658
def SetTransparency(self, amount):
660
Sets the alpha channel value for transparent windows.
662
:param integer `amount`: the actual transparency value (between 0 and 255).
664
:raise: `Exception` if the `amount` parameter is lower than ``0`` or greater than ``255``.
667
if self._transparency == amount:
670
if amount < 0 or amount > 255:
671
raise Exception("Invalid transparency value")
673
self._transparency = amount
676
def GetTransparency(self):
678
Returns the alpha channel value for transparent windows.
680
:return: An integer representing the alpha channel value.
683
return self._transparency
686
def ConvertToBitmap(self, xpm, alpha=None):
688
Convert the given image to a bitmap, optionally overlaying an alpha
691
:param `xpm`: a list of strings formatted as XPM;
692
:type `xpm`: list of strings
693
:param `alpha`: a list of alpha values, the same size as the xpm bitmap.
694
:type `alpha`: list of integers
696
:return: An instance of :class:`Bitmap`.
699
if alpha is not None:
701
img = wx.BitmapFromXPMData(xpm)
702
img = img.ConvertToImage()
703
x, y = img.GetWidth(), img.GetHeight()
707
img.SetAlpha(ii, jj, alpha[jj*x+ii])
711
stream = cStringIO.StringIO(xpm)
712
img = wx.ImageFromStream(stream)
714
return wx.BitmapFromImage(img)
717
def Initialize(self):
718
""" Initializes the bitmaps and colours. """
720
# create wxBitmaps from the xpm's
721
self._rightBottomCorner = self.ConvertToBitmap(shadow_center_xpm, shadow_center_alpha)
722
self._bottom = self.ConvertToBitmap(shadow_bottom_xpm, shadow_bottom_alpha)
723
self._bottomLeft = self.ConvertToBitmap(shadow_bottom_left_xpm, shadow_bottom_left_alpha)
724
self._rightTop = self.ConvertToBitmap(shadow_right_top_xpm, shadow_right_top_alpha)
725
self._right = self.ConvertToBitmap(shadow_right_xpm, shadow_right_alpha)
727
# initialise the colour map
729
self.SetMenuBarColour(self._menuBarColourScheme)
731
# Create common bitmaps
732
self.FillStockBitmaps()
735
def FillStockBitmaps(self):
736
""" Initializes few standard bitmaps. """
738
bmp = self.ConvertToBitmap(arrow_down, alpha=None)
739
bmp.SetMask(wx.Mask(bmp, wx.Colour(0, 128, 128)))
740
self._bitmaps.update({"arrow_down": bmp})
742
bmp = self.ConvertToBitmap(arrow_up, alpha=None)
743
bmp.SetMask(wx.Mask(bmp, wx.Colour(0, 128, 128)))
744
self._bitmaps.update({"arrow_up": bmp})
747
def GetStockBitmap(self, name):
749
Returns a bitmap from a stock.
751
:param string `name`: the bitmap name.
753
:return: The stock bitmap, if `name` was found in the stock bitmap dictionary.
754
Othewise, :class:`NullBitmap` is returned.
757
if self._bitmaps.has_key(name):
758
return self._bitmaps[name]
765
Accessor to the unique art manager object.
767
:return: A unique instance of :class:`ArtManager`.
770
if not hasattr(self, "_instance"):
772
self._instance = ArtManager()
773
self._instance.Initialize()
775
# Initialize the renderers map
776
self._renderers[StyleXP] = RendererXP()
777
self._renderers[Style2007] = RendererMSOffice2007()
779
return self._instance
781
Get = classmethod(Get)
784
""" Destructor for the unique art manager object. """
786
if hasattr(self, "_instance"):
790
Free = classmethod(Free)
793
def OnSysColourChange(self, event):
795
Handles the ``wx.EVT_SYS_COLOUR_CHANGED`` event for :class:`ArtManager`.
797
:param `event`: a :class:`SysColourChangedEvent` event to be processed.
800
# reinitialise the colour map
804
def LightColour(self, colour, percent):
806
Return light contrast of `colour`. The colour returned is from the scale of
809
:param `colour`: the input colour to be brightened, an instance of :class:`Colour`;
810
:param integer `percent`: determines how light the colour will be. `percent` = ``100``
811
returns white, `percent` = ``0`` returns `colour`.
813
:return: A light contrast of the input `colour`, an instance of :class:`Colour`.
816
end_colour = wx.WHITE
817
rd = end_colour.Red() - colour.Red()
818
gd = end_colour.Green() - colour.Green()
819
bd = end_colour.Blue() - colour.Blue()
822
# We take the percent way of the colour from colour -. white
824
r = colour.Red() + ((i*rd*100)/high)/100
825
g = colour.Green() + ((i*gd*100)/high)/100
826
b = colour.Blue() + ((i*bd*100)/high)/100
828
return wx.Colour(r, g, b)
831
def DarkColour(self, colour, percent):
833
Like the :meth:`~ArtManager.LightColour` function, but create the colour darker by `percent`.
835
:param `colour`: the input colour to be darkened, an instance of :class:`Colour`;
836
:param integer `percent`: determines how dark the colour will be. `percent` = ``100``
837
returns black, `percent` = ``0`` returns `colour`.
839
:return: A dark contrast of the input `colour`, an instance of :class:`Colour`.
842
end_colour = wx.BLACK
843
rd = end_colour.Red() - colour.Red()
844
gd = end_colour.Green() - colour.Green()
845
bd = end_colour.Blue() - colour.Blue()
848
# We take the percent way of the colour from colour -. white
850
r = colour.Red() + ((i*rd*100)/high)/100
851
g = colour.Green() + ((i*gd*100)/high)/100
852
b = colour.Blue() + ((i*bd*100)/high)/100
854
return wx.Colour(r, g, b)
857
def PaintStraightGradientBox(self, dc, rect, startColour, endColour, vertical=True):
859
Paint the rectangle with gradient colouring; the gradient lines are either
860
horizontal or vertical.
862
:param `dc`: an instance of :class:`DC`;
863
:param Rect `rect`: the rectangle to be filled with gradient shading;
864
:param Colour `startColour`: the first colour of the gradient shading;
865
:param Colour `endColour`: the second colour of the gradient shading;
866
:param bool `vertical`: ``True`` for gradient colouring in the vertical direction,
867
``False`` for horizontal shading.
870
dcsaver = DCSaver(dc)
873
high = rect.GetHeight()-1
876
high = rect.GetWidth()-1
882
dc.GradientFillLinear(rect, startColour, endColour, direction)
885
def PaintGradientRegion(self, dc, region, startColour, endColour, vertical=True):
887
Paint a region with gradient colouring.
889
:param `dc`: an instance of :class:`DC`;
890
:param `region`: a region to be filled with gradient shading (an instance of
892
:param Colour `startColour`: the first colour of the gradient shading;
893
:param Colour `endColour`: the second colour of the gradient shading;
894
:param bool `vertical`: ``True`` for gradient colouring in the vertical direction,
895
``False`` for horizontal shading.
899
# The way to achieve non-rectangle
900
memDC = wx.MemoryDC()
901
rect = region.GetBox()
902
bitmap = wx.EmptyBitmap(rect.width, rect.height)
903
memDC.SelectObject(bitmap)
905
# Colour the whole rectangle with gradient
906
rr = wx.Rect(0, 0, rect.width, rect.height)
907
self.PaintStraightGradientBox(memDC, rr, startColour, endColour, vertical)
909
# Convert the region to a black and white bitmap with the white pixels being inside the region
910
# we draw the bitmap over the gradient coloured rectangle, with mask set to white,
911
# this will cause our region to be coloured with the gradient, while area outside the
912
# region will be painted with black. then we simply draw the bitmap to the dc with mask set to
914
tmpRegion = wx.Region(rect.x, rect.y, rect.width, rect.height)
915
tmpRegion.Offset(-rect.x, -rect.y)
916
regionBmp = tmpRegion.ConvertToBitmap()
917
regionBmp.SetMask(wx.Mask(regionBmp, wx.WHITE))
919
# The function ConvertToBitmap() return a rectangle bitmap
920
# which is shorter by 1 pixl on the height and width (this is correct behavior, since
921
# DrawLine does not include the second point as part of the line)
922
# we fix this issue by drawing our own line at the bottom and left side of the rectangle
923
memDC.SetPen(wx.BLACK_PEN)
924
memDC.DrawBitmap(regionBmp, 0, 0, True)
925
memDC.DrawLine(0, rr.height - 1, rr.width, rr.height - 1)
926
memDC.DrawLine(rr.width - 1, 0, rr.width - 1, rr.height)
928
memDC.SelectObject(wx.NullBitmap)
929
bitmap.SetMask(wx.Mask(bitmap, wx.BLACK))
930
dc.DrawBitmap(bitmap, rect.x, rect.y, True)
933
def PaintDiagonalGradientBox(self, dc, rect, startColour, endColour,
934
startAtUpperLeft=True, trimToSquare=True):
936
Paint rectangle with gradient colouring; the gradient lines are diagonal
937
and may start from the upper left corner or from the upper right corner.
939
:param `dc`: an instance of :class:`DC`;
940
:param Rect `rect`: the rectangle to be filled with gradient shading;
941
:param Colour `startColour`: the first colour of the gradient shading;
942
:param Colour `endColour`: the second colour of the gradient shading;
943
:param bool `startAtUpperLeft`: ``True`` to start the gradient lines at the upper
944
left corner of the rectangle, ``False`` to start at the upper right corner;
945
:param bool `trimToSquare`: ``True`` to trim the gradient lines in a square.
948
# Save the current pen and brush
949
savedPen = dc.GetPen()
950
savedBrush = dc.GetBrush()
952
# gradient fill from colour 1 to colour 2 with top to bottom
953
if rect.height < 1 or rect.width < 1:
956
# calculate some basic numbers
961
if rect.width > rect.height:
966
sizeX = sizeY = rect.height - 1
970
proportion = float(rect.height)/float(rect.width)
972
sizeX = rect.width - 1
973
sizeY = rect.height -1
980
sizeX = sizeY = rect.width - 1
984
sizeX = rect.width - 1
986
sizeY = rect.height - 1
987
proportion = float(rect.width)/float(rect.height)
989
# calculate gradient coefficients
994
rstep = float(col2.Red() - col1.Red())/float(size)
995
gstep = float(col2.Green() - col1.Green())/float(size)
996
bstep = float(col2.Blue() - col1.Blue())/float(size)
998
# draw the upper triangle
999
for i in xrange(size):
1001
currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)
1002
dc.SetBrush(wx.Brush(currCol, wx.SOLID))
1003
dc.SetPen(wx.Pen(currCol))
1005
if startAtUpperLeft:
1007
if rect.width > rect.height:
1009
dc.DrawLine(rect.x + i, rect.y, rect.x, int(rect.y + proportion*i))
1010
dc.DrawPoint(rect.x, int(rect.y + proportion*i))
1014
dc.DrawLine(int(rect.x + proportion*i), rect.y, rect.x, rect.y + i)
1015
dc.DrawPoint(rect.x, rect.y + i)
1019
if rect.width > rect.height:
1021
dc.DrawLine(rect.x + sizeX - i, rect.y, rect.x + sizeX, int(rect.y + proportion*i))
1022
dc.DrawPoint(rect.x + sizeX, int(rect.y + proportion*i))
1026
xTo = (int(rect.x + sizeX - proportion * i) > rect.x and [int(rect.x + sizeX - proportion*i)] or [rect.x])[0]
1027
dc.DrawLine(xTo, rect.y, rect.x + sizeX, rect.y + i)
1028
dc.DrawPoint(rect.x + sizeX, rect.y + i)
1034
# draw the lower triangle
1035
for i in xrange(size):
1037
currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)
1038
dc.SetBrush(wx.Brush(currCol, wx.SOLID))
1039
dc.SetPen(wx.Pen(currCol))
1041
if startAtUpperLeft:
1043
if rect.width > rect.height:
1045
dc.DrawLine(rect.x + i, rect.y + sizeY, rect.x + sizeX, int(rect.y + proportion * i))
1046
dc.DrawPoint(rect.x + sizeX, int(rect.y + proportion * i))
1050
dc.DrawLine(int(rect.x + proportion * i), rect.y + sizeY, rect.x + sizeX, rect.y + i)
1051
dc.DrawPoint(rect.x + sizeX, rect.y + i)
1055
if rect.width > rect.height:
1057
dc.DrawLine(rect.x, (int)(rect.y + proportion * i), rect.x + sizeX - i, rect.y + sizeY)
1058
dc.DrawPoint(rect.x + sizeX - i, rect.y + sizeY)
1062
xTo = (int(rect.x + sizeX - proportion*i) > rect.x and [int(rect.x + sizeX - proportion*i)] or [rect.x])[0]
1063
dc.DrawLine(rect.x, rect.y + i, xTo, rect.y + sizeY)
1064
dc.DrawPoint(xTo, rect.y + sizeY)
1071
# Restore the pen and brush
1072
dc.SetPen( savedPen )
1073
dc.SetBrush( savedBrush )
1076
def PaintCrescentGradientBox(self, dc, rect, startColour, endColour, concave=True):
1078
Paint a region with gradient colouring. The gradient is in crescent shape
1079
which fits the 2007 style.
1081
:param `dc`: an instance of :class:`DC`;
1082
:param Rect `rect`: the rectangle to be filled with gradient shading;
1083
:param Colour `startColour`: the first colour of the gradient shading;
1084
:param Colour `endColour`: the second colour of the gradient shading;
1085
:param bool `concave`: ``True`` for a concave effect, ``False`` for a convex one.
1088
diagonalRectWidth = rect.GetWidth()/4
1089
spare = rect.width - 4*diagonalRectWidth
1090
leftRect = wx.Rect(rect.x, rect.y, diagonalRectWidth, rect.GetHeight())
1091
rightRect = wx.Rect(rect.x + 3 * diagonalRectWidth + spare, rect.y, diagonalRectWidth, rect.GetHeight())
1095
self.PaintStraightGradientBox(dc, rect, self.MixColours(startColour, endColour, 50), endColour)
1096
self.PaintDiagonalGradientBox(dc, leftRect, startColour, endColour, True, False)
1097
self.PaintDiagonalGradientBox(dc, rightRect, startColour, endColour, False, False)
1101
self.PaintStraightGradientBox(dc, rect, endColour, self.MixColours(endColour, startColour, 50))
1102
self.PaintDiagonalGradientBox(dc, leftRect, endColour, startColour, False, False)
1103
self.PaintDiagonalGradientBox(dc, rightRect, endColour, startColour, True, False)
1106
def FrameColour(self):
1108
Return the surrounding colour for a control.
1110
:return: An instance of :class:`Colour`.
1113
return wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
1116
def BackgroundColour(self):
1118
Returns the background colour of a control when not in focus.
1120
:return: An instance of :class:`Colour`.
1123
return self.LightColour(self.FrameColour(), 75)
1126
def HighlightBackgroundColour(self):
1128
Returns the background colour of a control when it is in focus.
1130
:return: An instance of :class:`Colour`.
1133
return self.LightColour(self.FrameColour(), 60)
1136
def MixColours(self, firstColour, secondColour, percent):
1138
Return mix of input colours.
1140
:param `firstColour`: the first colour to be mixed, an instance of :class:`Colour`;
1141
:param `secondColour`: the second colour to be mixed, an instance of :class:`Colour`;
1142
:param integer `percent`: the relative percentage of `firstColour` with respect to
1145
:return: An instance of :class:`Colour`.
1148
# calculate gradient coefficients
1149
redOffset = float((secondColour.Red() * (100 - percent) / 100) - (firstColour.Red() * percent / 100))
1150
greenOffset = float((secondColour.Green() * (100 - percent) / 100) - (firstColour.Green() * percent / 100))
1151
blueOffset = float((secondColour.Blue() * (100 - percent) / 100) - (firstColour.Blue() * percent / 100))
1153
return wx.Colour(firstColour.Red() + redOffset, firstColour.Green() + greenOffset,
1154
firstColour.Blue() + blueOffset)
1159
Creates a random colour.
1161
:return: An instance of :class:`Colour`.
1164
r = random.randint(0, 255) # Random value betweem 0-255
1165
g = random.randint(0, 255) # Random value betweem 0-255
1166
b = random.randint(0, 255) # Random value betweem 0-255
1168
return wx.Colour(r, g, b)
1171
def IsDark(self, colour):
1173
Returns whether a colour is dark or light.
1175
:param `colour`: an instance of :class:`Colour`.
1177
:return: ``True`` if the average RGB values are dark, ``False`` otherwise.
1180
evg = (colour.Red() + colour.Green() + colour.Blue())/3
1188
def TruncateText(self, dc, text, maxWidth):
1190
Truncates a given string to fit given width size. if the text does not fit
1191
into the given width it is truncated to fit. the format of the fixed text
1192
is <truncate text ...>.
1194
:param `dc`: an instance of :class:`DC`;
1195
:param string `text`: the text to be (eventually) truncated;
1196
:param integer `maxWidth`: the maximum width allowed for the text.
1198
:return: A new string containining the (possibly) truncated text.
1207
textW, textH = dc.GetTextExtent(text)
1209
if rectSize >= textW:
1212
# The text does not fit in the designated area,
1213
# so we need to truncate it a bit
1215
w, h = dc.GetTextExtent(suffix)
1218
for i in xrange(textLen, -1, -1):
1220
textW, textH = dc.GetTextExtent(tempText)
1221
if rectSize >= textW:
1222
fixedText = tempText
1226
tempText = tempText[:-1]
1229
def DrawButton(self, dc, rect, theme, state, input=None):
1231
Colour rectangle according to the theme.
1233
:param `dc`: an instance of :class:`DC`;
1234
:param Rect `rect`: the rectangle to be filled with gradient shading;
1235
:param string `theme`: the theme to use to draw the button;
1236
:param integer `state`: the button state;
1237
:param `input`: a flag used to call the right method.
1240
if input is None or type(input) == type(False):
1241
self.DrawButtonTheme(dc, rect, theme, state, input)
1243
self.DrawButtonColour(dc, rect, theme, state, input)
1246
def DrawButtonTheme(self, dc, rect, theme, state, useLightColours=True):
1248
Draws a button using the appropriate theme.
1250
:param `dc`: an instance of :class:`DC`;
1251
:param Rect `rect`: the button's client rectangle;
1252
:param string `theme`: the theme to use to draw the button;
1253
:param integer `state`: the button state;
1254
:param bool `useLightColours`: ``True`` to use light colours, ``False`` otherwise.
1257
renderer = self._renderers[theme]
1259
# Set background colour if non given by caller
1260
renderer.DrawButton(dc, rect, state, useLightColours)
1263
def DrawButtonColour(self, dc, rect, theme, state, colour):
1265
Draws a button using the appropriate theme.
1267
:param `dc`: an instance of :class:`DC`;
1268
:param Rect `rect`: the button's client rectangle;
1269
:param string `theme`: the theme to use to draw the button;
1270
:param integer `state`: the button state;
1271
:param `colour`: a valid :class:`Colour` instance.
1274
renderer = self._renderers[theme]
1275
renderer.DrawButton(dc, rect, state, colour)
1278
def CanMakeWindowsTransparent(self):
1282
:return: ``True`` if the system supports transparency of toplevel windows,
1283
otherwise returns ``False``.
1286
if wx.Platform == "__WXMSW__":
1288
version = wx.GetOsDescription()
1289
found = version.find("XP") >= 0 or version.find("2000") >= 0 or version.find("NT") >= 0
1292
elif wx.Platform == "__WXMAC__":
1298
# on supported windows systems (Win2000 and greater), this function
1299
# will make a frame window transparent by a certain amount
1300
def MakeWindowTransparent(self, wnd, amount):
1302
Used internally. Makes a toplevel window transparent if the system supports it.
1304
:param `wnd`: the toplevel window to make transparent, an instance of :class:`TopLevelWindow`;
1305
:param integer `amount`: the window transparency to apply.
1308
if wnd.GetSize() == (0, 0):
1311
# this API call is not in all SDKs, only the newer ones, so
1312
# we will runtime bind this
1313
if wx.Platform == "__WXMSW__":
1314
hwnd = wnd.GetHandle()
1316
if not hasattr(self, "_winlib"):
1317
if _libimported == "MH":
1318
self._winlib = win32api.LoadLibrary("user32")
1319
elif _libimported == "ctypes":
1320
self._winlib = ctypes.windll.user32
1322
if _libimported == "MH":
1323
pSetLayeredWindowAttributes = win32api.GetProcAddress(self._winlib,
1324
"SetLayeredWindowAttributes")
1326
if pSetLayeredWindowAttributes == None:
1329
exstyle = win32api.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
1330
if 0 == (exstyle & 0x80000):
1331
win32api.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, exstyle | 0x80000)
1333
winxpgui.SetLayeredWindowAttributes(hwnd, 0, amount, 2)
1335
elif _libimported == "ctypes":
1336
style = self._winlib.GetWindowLongA(hwnd, 0xffffffecL)
1338
self._winlib.SetWindowLongA(hwnd, 0xffffffecL, style)
1339
self._winlib.SetLayeredWindowAttributes(hwnd, 0, amount, 2)
1341
if not wnd.CanSetTransparent():
1343
wnd.SetTransparent(amount)
1347
# assumption: the background was already drawn on the dc
1348
def DrawBitmapShadow(self, dc, rect, where=BottomShadow|RightShadow):
1350
Draws a shadow using background bitmap.
1352
:param `dc`: an instance of :class:`DC`;
1353
:param Rect `rect`: the bitmap's client rectangle;
1354
:param integer `where`: where to draw the shadow. This can be any combination of the
1357
========================== ======= ================================
1358
Shadow Settings Value Description
1359
========================== ======= ================================
1360
``RightShadow`` 1 Right side shadow
1361
``BottomShadow`` 2 Not full bottom shadow
1362
``BottomShadowFull`` 4 Full bottom shadow
1363
========================== ======= ================================
1369
# the rect must be at least 5x5 pixles
1370
if rect.height < 2*shadowSize or rect.width < 2*shadowSize:
1373
# Start by drawing the right bottom corner
1374
if where & BottomShadow or where & BottomShadowFull:
1375
dc.DrawBitmap(self._rightBottomCorner, rect.x+rect.width, rect.y+rect.height, True)
1377
# Draw right side shadow
1378
xx = rect.x + rect.width
1379
yy = rect.y + rect.height - shadowSize
1381
if where & RightShadow:
1382
while yy - rect.y > 2*shadowSize:
1383
dc.DrawBitmap(self._right, xx, yy, True)
1386
dc.DrawBitmap(self._rightTop, xx, yy - shadowSize, True)
1388
if where & BottomShadow:
1389
xx = rect.x + rect.width - shadowSize
1390
yy = rect.height + rect.y
1391
while xx - rect.x > 2*shadowSize:
1392
dc.DrawBitmap(self._bottom, xx, yy, True)
1395
dc.DrawBitmap(self._bottomLeft, xx - shadowSize, yy, True)
1397
if where & BottomShadowFull:
1398
xx = rect.x + rect.width - shadowSize
1399
yy = rect.height + rect.y
1400
while xx - rect.x >= 0:
1401
dc.DrawBitmap(self._bottom, xx, yy, True)
1404
dc.DrawBitmap(self._bottom, xx, yy, True)
1407
def DropShadow(self, wnd, drop=True):
1409
Adds a shadow under the window (Windows only).
1411
:param `wnd`: the window for which we are dropping a shadow, an instance of :class:`TopLevelWindow`;
1412
:param bool `drop`: ``True`` to drop a shadow, ``False`` to remove it.
1415
if not self.CanMakeWindowsTransparent() or not _libimported:
1418
if "__WXMSW__" in wx.Platform:
1420
hwnd = wnd.GetHandle()
1422
if not hasattr(self, "_winlib"):
1423
if _libimported == "MH":
1424
self._winlib = win32api.LoadLibrary("user32")
1425
elif _libimported == "ctypes":
1426
self._winlib = ctypes.windll.user32
1428
if _libimported == "MH":
1429
csstyle = win32api.GetWindowLong(hwnd, win32con.GCL_STYLE)
1431
csstyle = self._winlib.GetWindowLongA(hwnd, win32con.GCL_STYLE)
1434
if csstyle & CS_DROPSHADOW:
1437
csstyle |= CS_DROPSHADOW #Nothing to be done
1441
if csstyle & CS_DROPSHADOW:
1442
csstyle &= ~(CS_DROPSHADOW)
1444
return #Nothing to be done
1446
win32api.SetWindowLong(hwnd, win32con.GCL_STYLE, csstyle)
1449
def GetBitmapStartLocation(self, dc, rect, bitmap, text="", style=0):
1451
Returns the top left `x` and `y` cordinates of the bitmap drawing.
1453
:param `dc`: an instance of :class:`DC`;
1454
:param Rect `rect`: the bitmap's client rectangle;
1455
:param Bitmap `bitmap`: the bitmap associated with the button;
1456
:param string `text`: the button label;
1457
:param integer `style`: the button style. This can be one of the following bits:
1459
============================== ======= ================================
1460
Button style Value Description
1461
============================== ======= ================================
1462
``BU_EXT_XP_STYLE`` 1 A button with a XP style
1463
``BU_EXT_2007_STYLE`` 2 A button with a MS Office 2007 style
1464
``BU_EXT_LEFT_ALIGN_STYLE`` 4 A left-aligned button
1465
``BU_EXT_CENTER_ALIGN_STYLE`` 8 A center-aligned button
1466
``BU_EXT_RIGHT_ALIGN_STYLE`` 16 A right-aligned button
1467
``BU_EXT_RIGHT_TO_LEFT_STYLE`` 32 A button suitable for right-to-left languages
1468
============================== ======= ================================
1470
:return: A tuple containining the top left `x` and `y` cordinates of the bitmap drawing.
1473
alignmentBuffer = self.GetAlignBuffer()
1475
# get the startLocationY
1476
fixedTextWidth = fixedTextHeight = 0
1479
fixedTextHeight = bitmap.GetHeight()
1481
fixedTextWidth, fixedTextHeight = dc.GetTextExtent(text)
1483
startLocationY = rect.y + (rect.height - fixedTextHeight)/2
1485
# get the startLocationX
1486
if style & BU_EXT_RIGHT_TO_LEFT_STYLE:
1488
startLocationX = rect.x + rect.width - alignmentBuffer - bitmap.GetWidth()
1492
if style & BU_EXT_RIGHT_ALIGN_STYLE:
1494
maxWidth = rect.x + rect.width - (2 * alignmentBuffer) - bitmap.GetWidth() # the alignment is for both sides
1496
# get the truncated text. The text may stay as is, it is not a must that is will be trancated
1497
fixedText = self.TruncateText(dc, text, maxWidth)
1499
# get the fixed text dimentions
1500
fixedTextWidth, fixedTextHeight = dc.GetTextExtent(fixedText)
1502
# calculate the start location
1503
startLocationX = maxWidth - fixedTextWidth
1505
elif style & BU_EXT_LEFT_ALIGN_STYLE:
1507
# calculate the start location
1508
startLocationX = alignmentBuffer
1510
else: # meaning BU_EXT_CENTER_ALIGN_STYLE
1512
maxWidth = rect.x + rect.width - (2 * alignmentBuffer) - bitmap.GetWidth() # the alignment is for both sides
1514
# get the truncated text. The text may stay as is, it is not a must that is will be trancated
1515
fixedText = self.TruncateText(dc, text, maxWidth)
1517
# get the fixed text dimentions
1518
fixedTextWidth, fixedTextHeight = dc.GetTextExtent(fixedText)
1520
if maxWidth > fixedTextWidth:
1522
# calculate the start location
1523
startLocationX = (maxWidth - fixedTextWidth) / 2
1527
# calculate the start location
1528
startLocationX = maxWidth - fixedTextWidth
1530
# it is very important to validate that the start location is not less than the alignment buffer
1531
if startLocationX < alignmentBuffer:
1532
startLocationX = alignmentBuffer
1534
return startLocationX, startLocationY
1537
def GetTextStartLocation(self, dc, rect, bitmap, text, style=0):
1539
Returns the top left `x` and `y` cordinates of the text drawing.
1540
In case the text is too long, the text is being fixed (the text is cut and
1541
a '...' mark is added in the end).
1543
:param `dc`: an instance of :class:`DC`;
1544
:param Rect `rect`: the text's client rectangle;
1545
:param Bitmap `bitmap`: the bitmap associated with the button;
1546
:param string `text`: the button label;
1547
:param integer `style`: the button style.
1549
:return: A tuple containining the top left `x` and `y` cordinates of the text drawing, plus
1550
the truncated version of the input `text`.
1552
:see: :meth:`~ArtManager.GetBitmapStartLocation` for a list of valid button styles.
1555
alignmentBuffer = self.GetAlignBuffer()
1557
# get the bitmap offset
1559
if bitmap != wx.NullBitmap:
1560
bitmapOffset = bitmap.GetWidth()
1562
# get the truncated text. The text may stay as is, it is not a must that is will be trancated
1563
maxWidth = rect.x + rect.width - (2 * alignmentBuffer) - bitmapOffset # the alignment is for both sides
1565
fixedText = self.TruncateText(dc, text, maxWidth)
1567
# get the fixed text dimentions
1568
fixedTextWidth, fixedTextHeight = dc.GetTextExtent(fixedText)
1569
startLocationY = (rect.height - fixedTextHeight) / 2 + rect.y
1571
# get the startLocationX
1572
if style & BU_EXT_RIGHT_TO_LEFT_STYLE:
1574
startLocationX = maxWidth - fixedTextWidth + alignmentBuffer
1578
if style & BU_EXT_LEFT_ALIGN_STYLE:
1580
# calculate the start location
1581
startLocationX = bitmapOffset + alignmentBuffer
1583
elif style & BU_EXT_RIGHT_ALIGN_STYLE:
1585
# calculate the start location
1586
startLocationX = maxWidth - fixedTextWidth + bitmapOffset + alignmentBuffer
1588
else: # meaning wxBU_EXT_CENTER_ALIGN_STYLE
1590
# calculate the start location
1591
startLocationX = (maxWidth - fixedTextWidth) / 2 + bitmapOffset + alignmentBuffer
1594
# it is very important to validate that the start location is not less than the alignment buffer
1595
if startLocationX < alignmentBuffer:
1596
startLocationX = alignmentBuffer
1598
return startLocationX, startLocationY, fixedText
1601
def DrawTextAndBitmap(self, dc, rect, text, enable=True, font=wx.NullFont,
1602
fontColour=wx.BLACK, bitmap=wx.NullBitmap,
1603
grayBitmap=wx.NullBitmap, style=0):
1605
Draws the text & bitmap on the input dc.
1607
:param `dc`: an instance of :class:`DC`;
1608
:param Rect `rect`: the text and bitmap client rectangle;
1609
:param string `text`: the button label;
1610
:param bool `enable`: ``True`` if the button is enabled, ``False`` otherwise;
1611
:param `font`: the font to use to draw the text, an instance of :class:`Font`;
1612
:param `fontColour`: the colour to use to draw the text, an instance of
1614
:param `bitmap`: the bitmap associated with the button, an instance of :class:`Bitmap`;
1615
:param `grayBitmap`: a greyed-out version of the input `bitmap` representing
1616
a disabled bitmap, an instance of :class:`Bitmap`;
1617
:param integer `style`: the button style.
1619
:see: :meth:`~ArtManager.GetBitmapStartLocation` for a list of valid button styles.
1624
dc.SetTextForeground(fontColour)
1626
dc.SetTextForeground(wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT))
1630
if font == wx.NullFont:
1631
font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
1635
startLocationX = startLocationY = 0
1637
if bitmap != wx.NullBitmap:
1639
# calculate the bitmap start location
1640
startLocationX, startLocationY = self.GetBitmapStartLocation(dc, rect, bitmap, text, style)
1644
dc.DrawBitmap(bitmap, startLocationX, startLocationY, True)
1646
dc.DrawBitmap(grayBitmap, startLocationX, startLocationY, True)
1648
# calculate the text start location
1649
location, labelOnly = self.GetAccelIndex(text)
1650
startLocationX, startLocationY, fixedText = self.GetTextStartLocation(dc, rect, bitmap, labelOnly, style)
1652
# after all the caculations are finished, it is time to draw the text
1653
# underline the first letter that is marked with a '&'
1654
if location == -1 or font.GetUnderlined() or location >= len(fixedText):
1656
dc.DrawText(fixedText, startLocationX, startLocationY)
1660
# underline the first '&'
1661
before = fixedText[0:location]
1662
underlineLetter = fixedText[location]
1663
after = fixedText[location+1:]
1666
dc.DrawText(before, startLocationX, startLocationY)
1669
if "__WXGTK__" not in wx.Platform:
1670
w1, h = dc.GetTextExtent(before)
1671
font.SetUnderlined(True)
1673
dc.DrawText(underlineLetter, startLocationX + w1, startLocationY)
1675
w1, h = dc.GetTextExtent(before)
1676
dc.DrawText(underlineLetter, startLocationX + w1, startLocationY)
1678
# Draw the underline ourselves since using the Underline in GTK,
1679
# causes the line to be too close to the letter
1680
uderlineLetterW, uderlineLetterH = dc.GetTextExtent(underlineLetter)
1682
curPen = dc.GetPen()
1683
dc.SetPen(wx.BLACK_PEN)
1685
dc.DrawLine(startLocationX + w1, startLocationY + uderlineLetterH - 2,
1686
startLocationX + w1 + uderlineLetterW, startLocationY + uderlineLetterH - 2)
1690
w2, h = dc.GetTextExtent(underlineLetter)
1691
font.SetUnderlined(False)
1693
dc.DrawText(after, startLocationX + w1 + w2, startLocationY)
1696
def CalcButtonBestSize(self, label, bmp):
1698
Returns the best fit size for the supplied label & bitmap.
1700
:param string `label`: the button label;
1701
:param `bmp`: the bitmap associated with the button, an instance of :class:`Bitmap`.
1703
:return: An instance of :class:`Size`, representing the best fit size for the supplied label & bitmap.
1706
if "__WXMSW__" in wx.Platform:
1712
dc.SelectBitmap(wx.EmptyBitmap(1, 1))
1714
dc.SetFont(wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT))
1715
width, height, dummy = dc.GetMultiLineTextExtent(label)
1717
width += 2*self.GetAlignBuffer()
1721
# allocate extra space for the bitmap
1722
heightBmp = bmp.GetHeight() + 2
1723
if height < heightBmp:
1726
width += bmp.GetWidth() + 2
1731
dc.SelectBitmap(wx.NullBitmap)
1733
return wx.Size(width, height)
1736
def GetMenuFaceColour(self):
1738
Returns the colour used for the menu foreground.
1740
:return: An instance of :class:`Colour`.
1743
renderer = self._renderers[self.GetMenuTheme()]
1744
return renderer.GetMenuFaceColour()
1747
def GetTextColourEnable(self):
1749
Returns the colour used for enabled menu items.
1751
:return: An instance of :class:`Colour`.
1754
renderer = self._renderers[self.GetMenuTheme()]
1755
return renderer.GetTextColourEnable()
1758
def GetTextColourDisable(self):
1760
Returns the colour used for disabled menu items.
1762
:return: An instance of :class:`Colour`.
1765
renderer = self._renderers[self.GetMenuTheme()]
1766
return renderer.GetTextColourDisable()
1771
Returns the font used by this theme.
1773
:return: An instance of :class:`Font`.
1776
renderer = self._renderers[self.GetMenuTheme()]
1777
return renderer.GetFont()
1780
def GetAccelIndex(self, label):
1782
Returns the mnemonic index of the label and the label stripped of the ampersand mnemonic
1783
(e.g. 'lab&el' ==> will result in 3 and labelOnly = label).
1785
:param string `label`: a string containining an ampersand.
1787
:return: A tuple containining the mnemonic index of the label and the label
1788
stripped of the ampersand mnemonic.
1793
indexAccel = label.find("&", indexAccel)
1794
if indexAccel == -1:
1795
return indexAccel, label
1796
if label[indexAccel:indexAccel+2] == "&&":
1797
label = label[0:indexAccel] + label[indexAccel+1:]
1802
labelOnly = label[0:indexAccel] + label[indexAccel+1:]
1804
return indexAccel, labelOnly
1807
def GetThemeBaseColour(self, useLightColours=True):
1809
Returns the theme (Blue, Silver, Green etc.) base colour, if no theme is active
1810
it return the active caption colour, lighter in 30%.
1812
:param bool `useLightColours`: ``True`` to use light colours, ``False`` otherwise.
1814
:return: An instance of :class:`Colour`.
1817
if not useLightColours and not self.IsDark(self.FrameColour()):
1818
return wx.NamedColour("GOLD")
1820
return self.LightColour(self.FrameColour(), 30)
1823
def GetAlignBuffer(self):
1825
Return the padding buffer for a text or bitmap.
1827
:return: An integer representing the padding buffer.
1830
return self._alignmentBuffer
1833
def SetMenuTheme(self, theme):
1835
Set the menu theme, possible values (Style2007, StyleXP, StyleVista).
1837
:param string `theme`: a rendering theme class, either `StyleXP`, `Style2007` or `StyleVista`.
1840
self._menuTheme = theme
1843
def GetMenuTheme(self):
1845
Returns the currently used menu theme.
1847
:return: A string containining the currently used theme for the menu.
1850
return self._menuTheme
1853
def AddMenuTheme(self, render):
1855
Adds a new theme to the stock.
1857
:param `render`: a rendering theme class, which must be derived from
1858
:class:`RendererBase`.
1860
:return: An integer representing the size of the renderers dictionary.
1864
lastRenderer = len(self._renderers)
1865
self._renderers[lastRenderer] = render
1870
def SetMS2007ButtonSunken(self, sunken):
1872
Sets MS 2007 button style sunken or not.
1874
:param bool `sunken`: ``True`` to have a sunken border effect, ``False`` otherwise.
1877
self._ms2007sunken = sunken
1880
def GetMS2007ButtonSunken(self):
1882
Returns the sunken flag for MS 2007 buttons.
1884
:return: ``True`` if the MS 2007 buttons are sunken, ``False`` otherwise.
1887
return self._ms2007sunken
1890
def GetMBVerticalGradient(self):
1891
""" Returns ``True`` if the menu bar should be painted with vertical gradient. """
1893
return self._verticalGradient
1896
def SetMBVerticalGradient(self, v):
1898
Sets the menu bar gradient style.
1900
:param bool `v`: ``True`` for a vertical shaded gradient, ``False`` otherwise.
1903
self._verticalGradient = v
1906
def DrawMenuBarBorder(self, border):
1908
Enables menu border drawing (XP style only).
1910
:param bool `border`: ``True`` to draw the menubar border, ``False`` otherwise.
1913
self._drowMBBorder = border
1916
def GetMenuBarBorder(self):
1918
Returns menu bar border drawing flag.
1920
:return: ``True`` if the menu bar border is to be drawn, ``False`` otherwise.
1923
return self._drowMBBorder
1926
def GetMenuBgFactor(self):
1928
Gets the visibility depth of the menu in Metallic style.
1929
The higher the value, the menu bar will look more raised
1932
return self._menuBgFactor
1935
def DrawDragSash(self, rect):
1939
:param Rect `rect`: the sash client rectangle.
1943
mem_dc = wx.MemoryDC()
1945
bmp = wx.EmptyBitmap(rect.width, rect.height)
1946
mem_dc.SelectObject(bmp)
1947
mem_dc.SetBrush(wx.WHITE_BRUSH)
1948
mem_dc.SetPen(wx.Pen(wx.WHITE, 1))
1949
mem_dc.DrawRectangle(0, 0, rect.width, rect.height)
1951
dc.Blit(rect.x, rect.y, rect.width, rect.height, mem_dc, 0, 0, wx.XOR)
1954
def TakeScreenShot(self, rect, bmp):
1956
Takes a screenshot of the screen at given position & size (rect).
1958
:param Rect `rect`: the screen rectangle we wish to capture;
1959
:param Bitmap `bmp`: currently unused.
1962
# Create a DC for the whole screen area
1963
dcScreen = wx.ScreenDC()
1965
# Create a Bitmap that will later on hold the screenshot image
1966
# Note that the Bitmap must have a size big enough to hold the screenshot
1967
# -1 means using the current default colour depth
1968
bmp = wx.EmptyBitmap(rect.width, rect.height)
1970
# Create a memory DC that will be used for actually taking the screenshot
1971
memDC = wx.MemoryDC()
1973
# Tell the memory DC to use our Bitmap
1974
# all drawing action on the memory DC will go to the Bitmap now
1975
memDC.SelectObject(bmp)
1977
# Blit (in this case copy) the actual screen on the memory DC
1978
# and thus the Bitmap
1979
memDC.Blit( 0, # Copy to this X coordinate
1980
0, # Copy to this Y coordinate
1981
rect.width, # Copy this width
1982
rect.height, # Copy this height
1983
dcScreen, # From where do we copy?
1984
rect.x, # What's the X offset in the original DC?
1985
rect.y # What's the Y offset in the original DC?
1988
# Select the Bitmap out of the memory DC by selecting a new
1989
# uninitialized Bitmap
1990
memDC.SelectObject(wx.NullBitmap)
1993
def DrawToolBarBg(self, dc, rect):
1995
Draws the toolbar background according to the active theme.
1997
:param `dc`: an instance of :class:`DC`;
1998
:param Rect `rect`: the toolbar's client rectangle.
2001
renderer = self._renderers[self.GetMenuTheme()]
2003
# Set background colour if non given by caller
2004
renderer.DrawToolBarBg(dc, rect)
2007
def DrawMenuBarBg(self, dc, rect):
2009
Draws the menu bar background according to the active theme.
2011
:param `dc`: an instance of :class:`DC`;
2012
:param Rect `rect`: the menubar's client rectangle.
2015
renderer = self._renderers[self.GetMenuTheme()]
2016
# Set background colour if non given by caller
2017
renderer.DrawMenuBarBg(dc, rect)
2020
def SetMenuBarColour(self, scheme):
2022
Sets the menu bar colour scheme to use.
2024
:param string `scheme`: a string representing a colour scheme (i.e., 'Default',
2025
'Dark', 'Dark Olive Green', 'Generic').
2028
self._menuBarColourScheme = scheme
2029
# set default colour
2030
if scheme in self._colourSchemeMap.keys():
2031
self._menuBarBgColour = self._colourSchemeMap[scheme]
2034
def GetMenuBarColourScheme(self):
2036
Returns the current colour scheme.
2038
:return: A string representing the current colour scheme.
2041
return self._menuBarColourScheme
2044
def GetMenuBarFaceColour(self):
2046
Returns the menu bar face colour.
2048
:return: An instance of :class:`Colour`.
2051
return self._menuBarBgColour
2054
def GetMenuBarSelectionColour(self):
2056
Returns the menu bar selection colour.
2058
:return: An instance of :class:`Colour`.
2061
return self._menuBarSelColour
2064
def InitColours(self):
2065
""" Initialise the colour map. """
2067
self._colourSchemeMap = {_("Default"): wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE),
2068
_("Dark"): wx.BLACK,
2069
_("Dark Olive Green"): wx.NamedColour("DARK OLIVE GREEN"),
2070
_("Generic"): wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)}
2073
def GetColourSchemes(self):
2075
Returns the available colour schemes.
2077
:return: A list of strings representing the available colour schemes.
2080
return self._colourSchemeMap.keys()
2083
def CreateGreyBitmap(self, bmp):
2085
Creates a grey bitmap image from the input bitmap.
2087
:param `bmp`: a valid :class:`Bitmap` object to be greyed out.
2089
:return: A greyed-out representation of the input bitmap, an instance of :class:`Bitmap`.
2092
img = bmp.ConvertToImage()
2093
return wx.BitmapFromImage(img.ConvertToGreyscale())
2096
def GetRaiseToolbar(self):
2097
""" Returns ``True`` if we are dropping a shadow under a toolbar. """
2099
return self._raiseTB
2102
def SetRaiseToolbar(self, rais):
2104
Enables/disables toobar shadow drop.
2106
:param bool `rais`: ``True`` to drop a shadow below a toolbar, ``False`` otherwise.
2109
self._raiseTB = rais