mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-28 14:12:52 -06:00
2109 lines
71 KiB
Python
Executable file
2109 lines
71 KiB
Python
Executable file
"""
|
|
This module contains drawing routines and customizations for the AGW widgets
|
|
:class:`~lib.agw.labelbook.LabelBook` and :class:`~lib.agw.flatmenu.FlatMenu`.
|
|
"""
|
|
|
|
import wx
|
|
import random
|
|
|
|
from wx.lib.six import BytesIO
|
|
|
|
from .fmresources import *
|
|
|
|
# ---------------------------------------------------------------------------- #
|
|
# Class DCSaver
|
|
# ---------------------------------------------------------------------------- #
|
|
|
|
_ = wx.GetTranslation
|
|
|
|
_libimported = None
|
|
|
|
if wx.Platform == "__WXMSW__":
|
|
osVersion = wx.GetOsVersion()
|
|
# Shadows behind menus are supported only in XP
|
|
if osVersion[1] == 5 and osVersion[2] == 1:
|
|
try:
|
|
import win32api
|
|
import win32con
|
|
import winxpgui
|
|
_libimported = "MH"
|
|
except:
|
|
try:
|
|
import ctypes
|
|
_libimported = "ctypes"
|
|
except:
|
|
pass
|
|
else:
|
|
_libimported = None
|
|
|
|
|
|
class DCSaver(object):
|
|
"""
|
|
Construct a DC saver. The dc is copied as-is.
|
|
"""
|
|
|
|
def __init__(self, pdc):
|
|
"""
|
|
Default class constructor.
|
|
|
|
:param `pdc`: an instance of :class:`DC`.
|
|
"""
|
|
|
|
self._pdc = pdc
|
|
self._pen = pdc.GetPen()
|
|
self._brush = pdc.GetBrush()
|
|
|
|
|
|
def __del__(self):
|
|
""" While destructing, restores the dc pen and brush. """
|
|
|
|
if self._pdc:
|
|
self._pdc.SetPen(self._pen)
|
|
self._pdc.SetBrush(self._brush)
|
|
|
|
|
|
# ---------------------------------------------------------------------------- #
|
|
# Class RendererBase
|
|
# ---------------------------------------------------------------------------- #
|
|
|
|
class RendererBase(object):
|
|
""" Base class for all theme renderers. """
|
|
|
|
def __init__(self):
|
|
""" Default class constructor. Intentionally empty. """
|
|
|
|
pass
|
|
|
|
|
|
def DrawButtonBorders(self, dc, rect, penColour, brushColour):
|
|
"""
|
|
Draws borders for buttons.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the button's client rectangle;
|
|
:param `penColour`: a valid :class:`Colour` for the pen border;
|
|
:param `brushColour`: a valid :class:`Colour` for the brush.
|
|
"""
|
|
|
|
# Keep old pen and brush
|
|
dcsaver = DCSaver(dc)
|
|
dc.SetPen(wx.Pen(penColour))
|
|
dc.SetBrush(wx.Brush(brushColour))
|
|
dc.DrawRectangle(rect)
|
|
|
|
|
|
def DrawBitmapArea(self, dc, xpm_name, rect, baseColour, flipSide):
|
|
"""
|
|
Draws the area below a bitmap and the bitmap itself using a gradient shading.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param string `xpm_name`: a name of a XPM bitmap;
|
|
:param Rect `rect`: the bitmap client rectangle;
|
|
:param `baseColour`: a valid :class:`Colour` for the bitmap background;
|
|
:param bool `flipSide`: ``True`` to flip the gradient direction, ``False`` otherwise.
|
|
"""
|
|
|
|
# draw the gradient area
|
|
if not flipSide:
|
|
ArtManager.Get().PaintDiagonalGradientBox(dc, rect, wx.WHITE,
|
|
ArtManager.Get().LightColour(baseColour, 20),
|
|
True, False)
|
|
else:
|
|
ArtManager.Get().PaintDiagonalGradientBox(dc, rect, ArtManager.Get().LightColour(baseColour, 20),
|
|
wx.WHITE, True, False)
|
|
|
|
# draw arrow
|
|
arrowDown = wx.Bitmap(xpm_name)
|
|
arrowDown.SetMask(wx.Mask(arrowDown, wx.WHITE))
|
|
dc.DrawBitmap(arrowDown, rect.x + 1 , rect.y + 1, True)
|
|
|
|
|
|
def DrawBitmapBorders(self, dc, rect, penColour, bitmapBorderUpperLeftPen):
|
|
"""
|
|
Draws borders for a bitmap.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the button's client rectangle;
|
|
:param `penColour`: a valid :class:`Colour` for the pen border;
|
|
:param `bitmapBorderUpperLeftPen`: a valid :class:`Colour` for the pen upper
|
|
left border.
|
|
"""
|
|
|
|
# Keep old pen and brush
|
|
dcsaver = DCSaver(dc)
|
|
|
|
# lower right size
|
|
dc.SetPen(wx.Pen(penColour))
|
|
dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1)
|
|
dc.DrawLine(rect.x + rect.width - 1, rect.y, rect.x + rect.width - 1, rect.y + rect.height)
|
|
|
|
# upper left side
|
|
dc.SetPen(wx.Pen(bitmapBorderUpperLeftPen))
|
|
dc.DrawLine(rect.x, rect.y, rect.x + rect.width, rect.y)
|
|
dc.DrawLine(rect.x, rect.y, rect.x, rect.y + rect.height)
|
|
|
|
|
|
def GetMenuFaceColour(self):
|
|
"""
|
|
Returns the foreground colour for the menu.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return ArtManager.Get().LightColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE), 80)
|
|
|
|
|
|
def GetTextColourEnable(self):
|
|
"""
|
|
Returns the colour used for text colour when enabled.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return wx.BLACK
|
|
|
|
|
|
def GetTextColourDisable(self):
|
|
"""
|
|
Returns the colour used for text colour when disabled.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return ArtManager.Get().LightColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT), 30)
|
|
|
|
|
|
def GetFont(self):
|
|
"""
|
|
Returns the font used for text.
|
|
|
|
:return: An instance of :class:`Font`.
|
|
"""
|
|
|
|
return wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
|
|
|
|
|
|
# ---------------------------------------------------------------------------- #
|
|
# Class RendererXP
|
|
# ---------------------------------------------------------------------------- #
|
|
|
|
class RendererXP(RendererBase):
|
|
""" Xp-Style renderer. """
|
|
|
|
def __init__(self):
|
|
""" Default class constructor. """
|
|
|
|
RendererBase.__init__(self)
|
|
|
|
|
|
def DrawButton(self, dc, rect, state, input=None):
|
|
"""
|
|
Draws a button using the XP theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the button's client rectangle;
|
|
:param integer `state`: the button state;
|
|
:param `input`: a flag used to call the right method.
|
|
"""
|
|
|
|
if input is None or type(input) == type(False):
|
|
self.DrawButtonTheme(dc, rect, state, input)
|
|
else:
|
|
self.DrawButtonColour(dc, rect, state, input)
|
|
|
|
|
|
def DrawButtonTheme(self, dc, rect, state, useLightColours=None):
|
|
"""
|
|
Draws a button using the XP theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the button's client rectangle;
|
|
:param integer `state`: the button state;
|
|
:param bool `useLightColours`: ``True`` to use light colours, ``False`` otherwise.
|
|
"""
|
|
|
|
# switch according to the status
|
|
if state == ControlFocus:
|
|
penColour = ArtManager.Get().FrameColour()
|
|
brushColour = ArtManager.Get().BackgroundColour()
|
|
elif state == ControlPressed:
|
|
penColour = ArtManager.Get().FrameColour()
|
|
brushColour = ArtManager.Get().HighlightBackgroundColour()
|
|
else:
|
|
penColour = ArtManager.Get().FrameColour()
|
|
brushColour = ArtManager.Get().BackgroundColour()
|
|
|
|
# Draw the button borders
|
|
self.DrawButtonBorders(dc, rect, penColour, brushColour)
|
|
|
|
|
|
def DrawButtonColour(self, dc, rect, state, colour):
|
|
"""
|
|
Draws a button using the XP theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the button's client rectangle;
|
|
:param integer `state`: the button state;
|
|
:param `colour`: a valid :class:`Colour` instance.
|
|
"""
|
|
|
|
# switch according to the status
|
|
if statet == ControlFocus:
|
|
penColour = colour
|
|
brushColour = ArtManager.Get().LightColour(colour, 75)
|
|
elif state == ControlPressed:
|
|
penColour = colour
|
|
brushColour = ArtManager.Get().LightColour(colour, 60)
|
|
else:
|
|
penColour = colour
|
|
brushColour = ArtManager.Get().LightColour(colour, 75)
|
|
|
|
# Draw the button borders
|
|
self.DrawButtonBorders(dc, rect, penColour, brushColour)
|
|
|
|
|
|
def DrawMenuBarBg(self, dc, rect):
|
|
"""
|
|
Draws the menu bar background according to the active theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the menu bar's client rectangle.
|
|
"""
|
|
|
|
# For office style, we simple draw a rectangle with a gradient colouring
|
|
artMgr = ArtManager.Get()
|
|
vertical = artMgr.GetMBVerticalGradient()
|
|
|
|
dcsaver = DCSaver(dc)
|
|
|
|
# fill with gradient
|
|
startColour = artMgr.GetMenuBarFaceColour()
|
|
if artMgr.IsDark(startColour):
|
|
startColour = artMgr.LightColour(startColour, 50)
|
|
|
|
endColour = artMgr.LightColour(startColour, 90)
|
|
artMgr.PaintStraightGradientBox(dc, rect, startColour, endColour, vertical)
|
|
|
|
# Draw the border
|
|
if artMgr.GetMenuBarBorder():
|
|
|
|
dc.SetPen(wx.Pen(startColour))
|
|
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
|
dc.DrawRectangle(rect)
|
|
|
|
|
|
def DrawToolBarBg(self, dc, rect):
|
|
"""
|
|
Draws the toolbar background according to the active theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the toolbar's client rectangle.
|
|
"""
|
|
|
|
artMgr = ArtManager.Get()
|
|
|
|
if not artMgr.GetRaiseToolbar():
|
|
return
|
|
|
|
# For office style, we simple draw a rectangle with a gradient colouring
|
|
vertical = artMgr.GetMBVerticalGradient()
|
|
|
|
dcsaver = DCSaver(dc)
|
|
|
|
# fill with gradient
|
|
startColour = artMgr.GetMenuBarFaceColour()
|
|
if artMgr.IsDark(startColour):
|
|
startColour = artMgr.LightColour(startColour, 50)
|
|
|
|
startColour = artMgr.LightColour(startColour, 20)
|
|
|
|
endColour = artMgr.LightColour(startColour, 90)
|
|
artMgr.PaintStraightGradientBox(dc, rect, startColour, endColour, vertical)
|
|
artMgr.DrawBitmapShadow(dc, rect)
|
|
|
|
|
|
def GetTextColourEnable(self):
|
|
"""
|
|
Returns the colour used for text colour when enabled.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return wx.BLACK
|
|
|
|
|
|
# ---------------------------------------------------------------------------- #
|
|
# Class RendererMSOffice2007
|
|
# ---------------------------------------------------------------------------- #
|
|
|
|
class RendererMSOffice2007(RendererBase):
|
|
""" Windows MS Office 2007 style. """
|
|
|
|
def __init__(self):
|
|
""" Default class constructor. """
|
|
|
|
RendererBase.__init__(self)
|
|
|
|
|
|
def GetColoursAccordingToState(self, state):
|
|
"""
|
|
Returns a :class:`Colour` according to the menu item state.
|
|
|
|
:param integer `state`: one of the following bits:
|
|
|
|
==================== ======= ==========================
|
|
Item State Value Description
|
|
==================== ======= ==========================
|
|
``ControlPressed`` 0 The item is pressed
|
|
``ControlFocus`` 1 The item is focused
|
|
``ControlDisabled`` 2 The item is disabled
|
|
``ControlNormal`` 3 Normal state
|
|
==================== ======= ==========================
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
# switch according to the status
|
|
if state == ControlFocus:
|
|
upperBoxTopPercent = 95
|
|
upperBoxBottomPercent = 50
|
|
lowerBoxTopPercent = 40
|
|
lowerBoxBottomPercent = 90
|
|
concaveUpperBox = True
|
|
concaveLowerBox = True
|
|
|
|
elif state == ControlPressed:
|
|
upperBoxTopPercent = 75
|
|
upperBoxBottomPercent = 90
|
|
lowerBoxTopPercent = 90
|
|
lowerBoxBottomPercent = 40
|
|
concaveUpperBox = True
|
|
concaveLowerBox = True
|
|
|
|
elif state == ControlDisabled:
|
|
upperBoxTopPercent = 100
|
|
upperBoxBottomPercent = 100
|
|
lowerBoxTopPercent = 70
|
|
lowerBoxBottomPercent = 70
|
|
concaveUpperBox = True
|
|
concaveLowerBox = True
|
|
|
|
else:
|
|
upperBoxTopPercent = 90
|
|
upperBoxBottomPercent = 50
|
|
lowerBoxTopPercent = 30
|
|
lowerBoxBottomPercent = 75
|
|
concaveUpperBox = True
|
|
concaveLowerBox = True
|
|
|
|
return upperBoxTopPercent, upperBoxBottomPercent, lowerBoxTopPercent, lowerBoxBottomPercent, \
|
|
concaveUpperBox, concaveLowerBox
|
|
|
|
|
|
def DrawButton(self, dc, rect, state, useLightColours):
|
|
"""
|
|
Draws a button using the MS Office 2007 theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the button's client rectangle;
|
|
:param integer `state`: the button state;
|
|
:param bool `useLightColours`: ``True`` to use light colours, ``False`` otherwise.
|
|
"""
|
|
|
|
self.DrawButtonColour(dc, rect, state, ArtManager.Get().GetThemeBaseColour(useLightColours))
|
|
|
|
|
|
def DrawButtonColour(self, dc, rect, state, colour):
|
|
"""
|
|
Draws a button using the MS Office 2007 theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the button's client rectangle;
|
|
:param integer `state`: the button state;
|
|
:param `colour`: a valid :class:`Colour` instance.
|
|
"""
|
|
|
|
artMgr = ArtManager.Get()
|
|
|
|
# Keep old pen and brush
|
|
dcsaver = DCSaver(dc)
|
|
|
|
# Define the rounded rectangle base on the given rect
|
|
# we need an array of 9 points for it
|
|
baseColour = colour
|
|
|
|
# Define the middle points
|
|
leftPt = wx.Point(rect.x, rect.y + (rect.height / 2))
|
|
rightPt = wx.Point(rect.x + rect.width-1, rect.y + (rect.height / 2))
|
|
|
|
# Define the top region
|
|
top = wx.Rect((rect.GetLeft(), rect.GetTop()), rightPt)
|
|
bottom = wx.Rect(leftPt, (rect.GetRight(), rect.GetBottom()))
|
|
|
|
upperBoxTopPercent, upperBoxBottomPercent, lowerBoxTopPercent, lowerBoxBottomPercent, \
|
|
concaveUpperBox, concaveLowerBox = self.GetColoursAccordingToState(state)
|
|
|
|
topStartColour = artMgr.LightColour(baseColour, upperBoxTopPercent)
|
|
topEndColour = artMgr.LightColour(baseColour, upperBoxBottomPercent)
|
|
bottomStartColour = artMgr.LightColour(baseColour, lowerBoxTopPercent)
|
|
bottomEndColour = artMgr.LightColour(baseColour, lowerBoxBottomPercent)
|
|
|
|
artMgr.PaintStraightGradientBox(dc, top, topStartColour, topEndColour)
|
|
artMgr.PaintStraightGradientBox(dc, bottom, bottomStartColour, bottomEndColour)
|
|
|
|
rr = wx.Rect(rect.x, rect.y, rect.width, rect.height)
|
|
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
|
|
|
frameColour = artMgr.LightColour(baseColour, 60)
|
|
dc.SetPen(wx.Pen(frameColour))
|
|
dc.DrawRectangle(rr)
|
|
|
|
wc = artMgr.LightColour(baseColour, 80)
|
|
dc.SetPen(wx.Pen(wc))
|
|
rr.Deflate(1, 1)
|
|
dc.DrawRectangle(rr)
|
|
|
|
|
|
def DrawMenuBarBg(self, dc, rect):
|
|
"""
|
|
Draws the menu bar background according to the active theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the menu bar's client rectangle.
|
|
"""
|
|
|
|
# Keep old pen and brush
|
|
dcsaver = DCSaver(dc)
|
|
artMgr = ArtManager.Get()
|
|
baseColour = artMgr.GetMenuBarFaceColour()
|
|
|
|
dc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)))
|
|
dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)))
|
|
dc.DrawRectangle(rect)
|
|
|
|
# Define the rounded rectangle base on the given rect
|
|
# we need an array of 9 points for it
|
|
regPts = [wx.Point() for ii in range(9)]
|
|
radius = 2
|
|
|
|
regPts[0] = wx.Point(rect.x, rect.y + radius)
|
|
regPts[1] = wx.Point(rect.x+radius, rect.y)
|
|
regPts[2] = wx.Point(rect.x+rect.width-radius-1, rect.y)
|
|
regPts[3] = wx.Point(rect.x+rect.width-1, rect.y + radius)
|
|
regPts[4] = wx.Point(rect.x+rect.width-1, rect.y + rect.height - radius - 1)
|
|
regPts[5] = wx.Point(rect.x+rect.width-radius-1, rect.y + rect.height-1)
|
|
regPts[6] = wx.Point(rect.x+radius, rect.y + rect.height-1)
|
|
regPts[7] = wx.Point(rect.x, rect.y + rect.height - radius - 1)
|
|
regPts[8] = regPts[0]
|
|
|
|
# Define the middle points
|
|
|
|
factor = artMgr.GetMenuBgFactor()
|
|
|
|
leftPt1 = wx.Point(rect.x, rect.y + (rect.height / factor))
|
|
leftPt2 = wx.Point(rect.x, rect.y + (rect.height / factor)*(factor-1))
|
|
|
|
rightPt1 = wx.Point(rect.x + rect.width, rect.y + (rect.height / factor))
|
|
rightPt2 = wx.Point(rect.x + rect.width, rect.y + (rect.height / factor)*(factor-1))
|
|
|
|
# Define the top region
|
|
topReg = [wx.Point() for ii in range(7)]
|
|
topReg[0] = regPts[0]
|
|
topReg[1] = regPts[1]
|
|
topReg[2] = wx.Point(regPts[2].x+1, regPts[2].y)
|
|
topReg[3] = wx.Point(regPts[3].x + 1, regPts[3].y)
|
|
topReg[4] = wx.Point(rightPt1.x, rightPt1.y+1)
|
|
topReg[5] = wx.Point(leftPt1.x, leftPt1.y+1)
|
|
topReg[6] = topReg[0]
|
|
|
|
# Define the middle region
|
|
middle = wx.Rect(leftPt1, wx.Point(rightPt2.x - 2, rightPt2.y))
|
|
|
|
# Define the bottom region
|
|
bottom = wx.Rect(leftPt2, wx.Point(rect.GetRight() - 1, rect.GetBottom()))
|
|
|
|
topStartColour = artMgr.LightColour(baseColour, 90)
|
|
topEndColour = artMgr.LightColour(baseColour, 60)
|
|
bottomStartColour = artMgr.LightColour(baseColour, 40)
|
|
bottomEndColour = artMgr.LightColour(baseColour, 20)
|
|
|
|
topRegion = wx.Region(topReg)
|
|
|
|
artMgr.PaintGradientRegion(dc, topRegion, topStartColour, topEndColour)
|
|
artMgr.PaintStraightGradientBox(dc, bottom, bottomStartColour, bottomEndColour)
|
|
artMgr.PaintStraightGradientBox(dc, middle, topEndColour, bottomStartColour)
|
|
|
|
|
|
def DrawToolBarBg(self, dc, rect):
|
|
"""
|
|
Draws the toolbar background according to the active theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the toolbar's client rectangle.
|
|
"""
|
|
|
|
artMgr = ArtManager.Get()
|
|
|
|
if not artMgr.GetRaiseToolbar():
|
|
return
|
|
|
|
# Keep old pen and brush
|
|
dcsaver = DCSaver(dc)
|
|
|
|
baseColour = artMgr.GetMenuBarFaceColour()
|
|
baseColour = artMgr.LightColour(baseColour, 20)
|
|
|
|
dc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)))
|
|
dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)))
|
|
dc.DrawRectangle(rect)
|
|
|
|
radius = 2
|
|
|
|
# Define the rounded rectangle base on the given rect
|
|
# we need an array of 9 points for it
|
|
regPts = [None]*9
|
|
|
|
regPts[0] = wx.Point(rect.x, rect.y + radius)
|
|
regPts[1] = wx.Point(rect.x+radius, rect.y)
|
|
regPts[2] = wx.Point(rect.x+rect.width-radius-1, rect.y)
|
|
regPts[3] = wx.Point(rect.x+rect.width-1, rect.y + radius)
|
|
regPts[4] = wx.Point(rect.x+rect.width-1, rect.y + rect.height - radius - 1)
|
|
regPts[5] = wx.Point(rect.x+rect.width-radius-1, rect.y + rect.height-1)
|
|
regPts[6] = wx.Point(rect.x+radius, rect.y + rect.height-1)
|
|
regPts[7] = wx.Point(rect.x, rect.y + rect.height - radius - 1)
|
|
regPts[8] = regPts[0]
|
|
|
|
# Define the middle points
|
|
factor = artMgr.GetMenuBgFactor()
|
|
|
|
leftPt1 = wx.Point(rect.x, rect.y + (rect.height / factor))
|
|
rightPt1 = wx.Point(rect.x + rect.width, rect.y + (rect.height / factor))
|
|
|
|
leftPt2 = wx.Point(rect.x, rect.y + (rect.height / factor)*(factor-1))
|
|
rightPt2 = wx.Point(rect.x + rect.width, rect.y + (rect.height / factor)*(factor-1))
|
|
|
|
# Define the top region
|
|
topReg = [None]*7
|
|
topReg[0] = regPts[0]
|
|
topReg[1] = regPts[1]
|
|
topReg[2] = wx.Point(regPts[2].x+1, regPts[2].y)
|
|
topReg[3] = wx.Point(regPts[3].x + 1, regPts[3].y)
|
|
topReg[4] = wx.Point(rightPt1.x, rightPt1.y+1)
|
|
topReg[5] = wx.Point(leftPt1.x, leftPt1.y+1)
|
|
topReg[6] = topReg[0]
|
|
|
|
# Define the middle region
|
|
middle = wx.Rect(leftPt1, wx.Point(rightPt2.x - 2, rightPt2.y))
|
|
|
|
# Define the bottom region
|
|
bottom = wx.Rect(leftPt2, wx.Point(rect.GetRight() - 1, rect.GetBottom()))
|
|
|
|
topStartColour = artMgr.LightColour(baseColour, 90)
|
|
topEndColour = artMgr.LightColour(baseColour, 60)
|
|
bottomStartColour = artMgr.LightColour(baseColour, 40)
|
|
bottomEndColour = artMgr.LightColour(baseColour, 20)
|
|
|
|
topRegion = wx.Region(topReg)
|
|
|
|
artMgr.PaintGradientRegion(dc, topRegion, topStartColour, topEndColour)
|
|
artMgr.PaintStraightGradientBox(dc, bottom, bottomStartColour, bottomEndColour)
|
|
artMgr.PaintStraightGradientBox(dc, middle, topEndColour, bottomStartColour)
|
|
|
|
artMgr.DrawBitmapShadow(dc, rect)
|
|
|
|
|
|
def GetTextColourEnable(self):
|
|
"""
|
|
Returns the colour used for text colour when enabled.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return wx.Colour("MIDNIGHT BLUE")
|
|
|
|
|
|
# ---------------------------------------------------------------------------- #
|
|
# Class ArtManager
|
|
# ---------------------------------------------------------------------------- #
|
|
|
|
class ArtManager(wx.EvtHandler):
|
|
|
|
"""
|
|
This class provides various art utilities, such as creating shadow, providing
|
|
lighter / darker colours for a given colour, etc...
|
|
"""
|
|
|
|
_alignmentBuffer = 7
|
|
_menuTheme = StyleXP
|
|
_verticalGradient = False
|
|
_renderers = {StyleXP: None, Style2007: None}
|
|
_bmpShadowEnabled = False
|
|
_ms2007sunken = False
|
|
_drowMBBorder = True
|
|
_menuBgFactor = 5
|
|
_menuBarColourScheme = _("Default")
|
|
_raiseTB = True
|
|
_bitmaps = {}
|
|
_transparency = 255
|
|
|
|
def __init__(self):
|
|
""" Default class constructor. """
|
|
|
|
wx.EvtHandler.__init__(self)
|
|
self._menuBarBgColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)
|
|
|
|
# connect an event handler to the system colour change event
|
|
self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChange)
|
|
|
|
|
|
def SetTransparency(self, amount):
|
|
"""
|
|
Sets the alpha channel value for transparent windows.
|
|
|
|
:param integer `amount`: the actual transparency value (between 0 and 255).
|
|
|
|
:raise: `Exception` if the `amount` parameter is lower than ``0`` or greater than ``255``.
|
|
"""
|
|
|
|
if self._transparency == amount:
|
|
return
|
|
|
|
if amount < 0 or amount > 255:
|
|
raise Exception("Invalid transparency value")
|
|
|
|
self._transparency = amount
|
|
|
|
|
|
def GetTransparency(self):
|
|
"""
|
|
Returns the alpha channel value for transparent windows.
|
|
|
|
:return: An integer representing the alpha channel value.
|
|
"""
|
|
|
|
return self._transparency
|
|
|
|
|
|
def ConvertToBitmap(self, xpm, alpha=None):
|
|
"""
|
|
Convert the given image to a bitmap, optionally overlaying an alpha
|
|
channel to it.
|
|
|
|
:param `xpm`: a list of strings formatted as XPM;
|
|
:type `xpm`: list of strings
|
|
:param `alpha`: a list of alpha values, the same size as the xpm bitmap.
|
|
:type `alpha`: list of integers
|
|
|
|
:return: An instance of :class:`Bitmap`.
|
|
"""
|
|
|
|
if alpha is not None:
|
|
|
|
img = wx.Bitmap(xpm)
|
|
img = img.ConvertToImage()
|
|
x, y = img.GetWidth(), img.GetHeight()
|
|
img.InitAlpha()
|
|
for jj in range(y):
|
|
for ii in range(x):
|
|
img.SetAlpha(ii, jj, alpha[jj*x+ii])
|
|
|
|
else:
|
|
|
|
stream = BytesIO(xpm)
|
|
img = wx.Image(stream)
|
|
|
|
return wx.Bitmap(img)
|
|
|
|
|
|
def Initialize(self):
|
|
""" Initializes the bitmaps and colours. """
|
|
|
|
# create wxBitmaps from the xpm's
|
|
self._rightBottomCorner = self.ConvertToBitmap(shadow_center_xpm, shadow_center_alpha)
|
|
self._bottom = self.ConvertToBitmap(shadow_bottom_xpm, shadow_bottom_alpha)
|
|
self._bottomLeft = self.ConvertToBitmap(shadow_bottom_left_xpm, shadow_bottom_left_alpha)
|
|
self._rightTop = self.ConvertToBitmap(shadow_right_top_xpm, shadow_right_top_alpha)
|
|
self._right = self.ConvertToBitmap(shadow_right_xpm, shadow_right_alpha)
|
|
|
|
# initialise the colour map
|
|
self.InitColours()
|
|
self.SetMenuBarColour(self._menuBarColourScheme)
|
|
|
|
# Create common bitmaps
|
|
self.FillStockBitmaps()
|
|
|
|
|
|
def FillStockBitmaps(self):
|
|
""" Initializes few standard bitmaps. """
|
|
|
|
bmp = self.ConvertToBitmap(arrow_down, alpha=None)
|
|
bmp.SetMask(wx.Mask(bmp, wx.Colour(0, 128, 128)))
|
|
self._bitmaps.update({"arrow_down": bmp})
|
|
|
|
bmp = self.ConvertToBitmap(arrow_up, alpha=None)
|
|
bmp.SetMask(wx.Mask(bmp, wx.Colour(0, 128, 128)))
|
|
self._bitmaps.update({"arrow_up": bmp})
|
|
|
|
|
|
def GetStockBitmap(self, name):
|
|
"""
|
|
Returns a bitmap from a stock.
|
|
|
|
:param string `name`: the bitmap name.
|
|
|
|
:return: The stock bitmap, if `name` was found in the stock bitmap dictionary.
|
|
Othewise, :class:`NullBitmap` is returned.
|
|
"""
|
|
|
|
return self._bitmaps.get(name, wx.NullBitmap)
|
|
|
|
|
|
def Get(self):
|
|
"""
|
|
Accessor to the unique art manager object.
|
|
|
|
:return: A unique instance of :class:`ArtManager`.
|
|
"""
|
|
|
|
if not hasattr(self, "_instance"):
|
|
|
|
self._instance = ArtManager()
|
|
self._instance.Initialize()
|
|
|
|
# Initialize the renderers map
|
|
self._renderers[StyleXP] = RendererXP()
|
|
self._renderers[Style2007] = RendererMSOffice2007()
|
|
|
|
return self._instance
|
|
|
|
Get = classmethod(Get)
|
|
|
|
def Free(self):
|
|
""" Destructor for the unique art manager object. """
|
|
|
|
if hasattr(self, "_instance"):
|
|
|
|
del self._instance
|
|
|
|
Free = classmethod(Free)
|
|
|
|
|
|
def OnSysColourChange(self, event):
|
|
"""
|
|
Handles the ``wx.EVT_SYS_COLOUR_CHANGED`` event for :class:`ArtManager`.
|
|
|
|
:param `event`: a :class:`SysColourChangedEvent` event to be processed.
|
|
"""
|
|
|
|
# reinitialise the colour map
|
|
self.InitColours()
|
|
|
|
|
|
def LightColour(self, colour, percent):
|
|
"""
|
|
Return light contrast of `colour`. The colour returned is from the scale of
|
|
`colour` ==> white.
|
|
|
|
:param `colour`: the input colour to be brightened, an instance of :class:`Colour`;
|
|
:param integer `percent`: determines how light the colour will be. `percent` = ``100``
|
|
returns white, `percent` = ``0`` returns `colour`.
|
|
|
|
:return: A light contrast of the input `colour`, an instance of :class:`Colour`.
|
|
"""
|
|
|
|
end_colour = wx.WHITE
|
|
rd = end_colour.Red() - colour.Red()
|
|
gd = end_colour.Green() - colour.Green()
|
|
bd = end_colour.Blue() - colour.Blue()
|
|
high = 100
|
|
|
|
# We take the percent way of the colour from colour -. white
|
|
i = percent
|
|
r = colour.Red() + ((i*rd*100)/high)/100
|
|
g = colour.Green() + ((i*gd*100)/high)/100
|
|
b = colour.Blue() + ((i*bd*100)/high)/100
|
|
|
|
return wx.Colour(int(r), int(g), int(b))
|
|
|
|
|
|
def DarkColour(self, colour, percent):
|
|
"""
|
|
Like the :meth:`~ArtManager.LightColour` function, but create the colour darker by `percent`.
|
|
|
|
:param `colour`: the input colour to be darkened, an instance of :class:`Colour`;
|
|
:param integer `percent`: determines how dark the colour will be. `percent` = ``100``
|
|
returns black, `percent` = ``0`` returns `colour`.
|
|
|
|
:return: A dark contrast of the input `colour`, an instance of :class:`Colour`.
|
|
"""
|
|
|
|
end_colour = wx.BLACK
|
|
rd = end_colour.Red() - colour.Red()
|
|
gd = end_colour.Green() - colour.Green()
|
|
bd = end_colour.Blue() - colour.Blue()
|
|
high = 100
|
|
|
|
# We take the percent way of the colour from colour -. white
|
|
i = percent
|
|
r = colour.Red() + ((i*rd*100)/high)/100
|
|
g = colour.Green() + ((i*gd*100)/high)/100
|
|
b = colour.Blue() + ((i*bd*100)/high)/100
|
|
|
|
return wx.Colour(int(r), int(g), int(b))
|
|
|
|
|
|
def PaintStraightGradientBox(self, dc, rect, startColour, endColour, vertical=True):
|
|
"""
|
|
Paint the rectangle with gradient colouring; the gradient lines are either
|
|
horizontal or vertical.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the rectangle to be filled with gradient shading;
|
|
:param Colour `startColour`: the first colour of the gradient shading;
|
|
:param Colour `endColour`: the second colour of the gradient shading;
|
|
:param bool `vertical`: ``True`` for gradient colouring in the vertical direction,
|
|
``False`` for horizontal shading.
|
|
"""
|
|
|
|
dcsaver = DCSaver(dc)
|
|
|
|
if vertical:
|
|
high = rect.GetHeight()-1
|
|
direction = wx.SOUTH
|
|
else:
|
|
high = rect.GetWidth()-1
|
|
direction = wx.EAST
|
|
|
|
if high < 1:
|
|
return
|
|
|
|
dc.GradientFillLinear(rect, startColour, endColour, direction)
|
|
|
|
|
|
def PaintGradientRegion(self, dc, region, startColour, endColour, vertical=True):
|
|
"""
|
|
Paint a region with gradient colouring.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param `region`: a region to be filled with gradient shading (an instance of
|
|
:class:`Region`);
|
|
:param Colour `startColour`: the first colour of the gradient shading;
|
|
:param Colour `endColour`: the second colour of the gradient shading;
|
|
:param bool `vertical`: ``True`` for gradient colouring in the vertical direction,
|
|
``False`` for horizontal shading.
|
|
|
|
"""
|
|
|
|
# The way to achieve non-rectangle
|
|
memDC = wx.MemoryDC()
|
|
rect = region.GetBox()
|
|
bitmap = wx.Bitmap(rect.width, rect.height)
|
|
memDC.SelectObject(bitmap)
|
|
|
|
# Colour the whole rectangle with gradient
|
|
rr = wx.Rect(0, 0, rect.width, rect.height)
|
|
self.PaintStraightGradientBox(memDC, rr, startColour, endColour, vertical)
|
|
|
|
# Convert the region to a black and white bitmap with the white pixels being inside the region
|
|
# we draw the bitmap over the gradient coloured rectangle, with mask set to white,
|
|
# this will cause our region to be coloured with the gradient, while area outside the
|
|
# region will be painted with black. then we simply draw the bitmap to the dc with mask set to
|
|
# black
|
|
tmpRegion = wx.Region(rect.x, rect.y, rect.width, rect.height)
|
|
tmpRegion.Offset(-rect.x, -rect.y)
|
|
regionBmp = tmpRegion.ConvertToBitmap()
|
|
regionBmp.SetMask(wx.Mask(regionBmp, wx.WHITE))
|
|
|
|
# The function ConvertToBitmap() return a rectangle bitmap
|
|
# which is shorter by 1 pixl on the height and width (this is correct behavior, since
|
|
# DrawLine does not include the second point as part of the line)
|
|
# we fix this issue by drawing our own line at the bottom and left side of the rectangle
|
|
memDC.SetPen(wx.BLACK_PEN)
|
|
memDC.DrawBitmap(regionBmp, 0, 0, True)
|
|
memDC.DrawLine(0, rr.height - 1, rr.width, rr.height - 1)
|
|
memDC.DrawLine(rr.width - 1, 0, rr.width - 1, rr.height)
|
|
|
|
memDC.SelectObject(wx.NullBitmap)
|
|
bitmap.SetMask(wx.Mask(bitmap, wx.BLACK))
|
|
dc.DrawBitmap(bitmap, rect.x, rect.y, True)
|
|
|
|
|
|
def PaintDiagonalGradientBox(self, dc, rect, startColour, endColour,
|
|
startAtUpperLeft=True, trimToSquare=True):
|
|
"""
|
|
Paint rectangle with gradient colouring; the gradient lines are diagonal
|
|
and may start from the upper left corner or from the upper right corner.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the rectangle to be filled with gradient shading;
|
|
:param Colour `startColour`: the first colour of the gradient shading;
|
|
:param Colour `endColour`: the second colour of the gradient shading;
|
|
:param bool `startAtUpperLeft`: ``True`` to start the gradient lines at the upper
|
|
left corner of the rectangle, ``False`` to start at the upper right corner;
|
|
:param bool `trimToSquare`: ``True`` to trim the gradient lines in a square.
|
|
"""
|
|
|
|
# Save the current pen and brush
|
|
savedPen = dc.GetPen()
|
|
savedBrush = dc.GetBrush()
|
|
|
|
# gradient fill from colour 1 to colour 2 with top to bottom
|
|
if rect.height < 1 or rect.width < 1:
|
|
return
|
|
|
|
# calculate some basic numbers
|
|
size = rect.width
|
|
sizeX = sizeY = 0
|
|
proportion = 1
|
|
|
|
if rect.width > rect.height:
|
|
|
|
if trimToSquare:
|
|
|
|
size = rect.height
|
|
sizeX = sizeY = rect.height - 1
|
|
|
|
else:
|
|
|
|
proportion = float(rect.height)/float(rect.width)
|
|
size = rect.width
|
|
sizeX = rect.width - 1
|
|
sizeY = rect.height -1
|
|
|
|
else:
|
|
|
|
if trimToSquare:
|
|
|
|
size = rect.width
|
|
sizeX = sizeY = rect.width - 1
|
|
|
|
else:
|
|
|
|
sizeX = rect.width - 1
|
|
size = rect.height
|
|
sizeY = rect.height - 1
|
|
proportion = float(rect.width)/float(rect.height)
|
|
|
|
# calculate gradient coefficients
|
|
col2 = endColour
|
|
col1 = startColour
|
|
|
|
rf, gf, bf = 0, 0, 0
|
|
rstep = float(col2.Red() - col1.Red())/float(size)
|
|
gstep = float(col2.Green() - col1.Green())/float(size)
|
|
bstep = float(col2.Blue() - col1.Blue())/float(size)
|
|
|
|
# draw the upper triangle
|
|
for i in range(size):
|
|
|
|
currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)
|
|
dc.SetBrush(wx.Brush(currCol, wx.SOLID))
|
|
dc.SetPen(wx.Pen(currCol))
|
|
|
|
if startAtUpperLeft:
|
|
|
|
if rect.width > rect.height:
|
|
|
|
dc.DrawLine(rect.x + i, rect.y, rect.x, int(rect.y + proportion*i))
|
|
dc.DrawPoint(rect.x, int(rect.y + proportion*i))
|
|
|
|
else:
|
|
|
|
dc.DrawLine(int(rect.x + proportion*i), rect.y, rect.x, rect.y + i)
|
|
dc.DrawPoint(rect.x, rect.y + i)
|
|
|
|
else:
|
|
|
|
if rect.width > rect.height:
|
|
|
|
dc.DrawLine(rect.x + sizeX - i, rect.y, rect.x + sizeX, int(rect.y + proportion*i))
|
|
dc.DrawPoint(rect.x + sizeX, int(rect.y + proportion*i))
|
|
|
|
else:
|
|
|
|
xTo = (int(rect.x + sizeX - proportion * i) > rect.x and [int(rect.x + sizeX - proportion*i)] or [rect.x])[0]
|
|
dc.DrawLine(xTo, rect.y, rect.x + sizeX, rect.y + i)
|
|
dc.DrawPoint(rect.x + sizeX, rect.y + i)
|
|
|
|
rf += rstep/2
|
|
gf += gstep/2
|
|
bf += bstep/2
|
|
|
|
# draw the lower triangle
|
|
for i in range(size):
|
|
|
|
currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)
|
|
dc.SetBrush(wx.Brush(currCol, wx.SOLID))
|
|
dc.SetPen(wx.Pen(currCol))
|
|
|
|
if startAtUpperLeft:
|
|
|
|
if rect.width > rect.height:
|
|
|
|
dc.DrawLine(rect.x + i, rect.y + sizeY, rect.x + sizeX, int(rect.y + proportion * i))
|
|
dc.DrawPoint(rect.x + sizeX, int(rect.y + proportion * i))
|
|
|
|
else:
|
|
|
|
dc.DrawLine(int(rect.x + proportion * i), rect.y + sizeY, rect.x + sizeX, rect.y + i)
|
|
dc.DrawPoint(rect.x + sizeX, rect.y + i)
|
|
|
|
else:
|
|
|
|
if rect.width > rect.height:
|
|
|
|
dc.DrawLine(rect.x, (int)(rect.y + proportion * i), rect.x + sizeX - i, rect.y + sizeY)
|
|
dc.DrawPoint(rect.x + sizeX - i, rect.y + sizeY)
|
|
|
|
else:
|
|
|
|
xTo = (int(rect.x + sizeX - proportion*i) > rect.x and [int(rect.x + sizeX - proportion*i)] or [rect.x])[0]
|
|
dc.DrawLine(rect.x, rect.y + i, xTo, rect.y + sizeY)
|
|
dc.DrawPoint(xTo, rect.y + sizeY)
|
|
|
|
rf += rstep/2
|
|
gf += gstep/2
|
|
bf += bstep/2
|
|
|
|
|
|
# Restore the pen and brush
|
|
dc.SetPen( savedPen )
|
|
dc.SetBrush( savedBrush )
|
|
|
|
|
|
def PaintCrescentGradientBox(self, dc, rect, startColour, endColour, concave=True):
|
|
"""
|
|
Paint a region with gradient colouring. The gradient is in crescent shape
|
|
which fits the 2007 style.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the rectangle to be filled with gradient shading;
|
|
:param Colour `startColour`: the first colour of the gradient shading;
|
|
:param Colour `endColour`: the second colour of the gradient shading;
|
|
:param bool `concave`: ``True`` for a concave effect, ``False`` for a convex one.
|
|
"""
|
|
|
|
diagonalRectWidth = rect.GetWidth()/4
|
|
spare = rect.width - 4*diagonalRectWidth
|
|
leftRect = wx.Rect(rect.x, rect.y, diagonalRectWidth, rect.GetHeight())
|
|
rightRect = wx.Rect(rect.x + 3 * diagonalRectWidth + spare, rect.y, diagonalRectWidth, rect.GetHeight())
|
|
|
|
if concave:
|
|
|
|
self.PaintStraightGradientBox(dc, rect, self.MixColours(startColour, endColour, 50), endColour)
|
|
self.PaintDiagonalGradientBox(dc, leftRect, startColour, endColour, True, False)
|
|
self.PaintDiagonalGradientBox(dc, rightRect, startColour, endColour, False, False)
|
|
|
|
else:
|
|
|
|
self.PaintStraightGradientBox(dc, rect, endColour, self.MixColours(endColour, startColour, 50))
|
|
self.PaintDiagonalGradientBox(dc, leftRect, endColour, startColour, False, False)
|
|
self.PaintDiagonalGradientBox(dc, rightRect, endColour, startColour, True, False)
|
|
|
|
|
|
def FrameColour(self):
|
|
"""
|
|
Return the surrounding colour for a control.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
|
|
|
|
|
|
def BackgroundColour(self):
|
|
"""
|
|
Returns the background colour of a control when not in focus.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return self.LightColour(self.FrameColour(), 75)
|
|
|
|
|
|
def HighlightBackgroundColour(self):
|
|
"""
|
|
Returns the background colour of a control when it is in focus.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return self.LightColour(self.FrameColour(), 60)
|
|
|
|
|
|
def MixColours(self, firstColour, secondColour, percent):
|
|
"""
|
|
Return mix of input colours.
|
|
|
|
:param `firstColour`: the first colour to be mixed, an instance of :class:`Colour`;
|
|
:param `secondColour`: the second colour to be mixed, an instance of :class:`Colour`;
|
|
:param integer `percent`: the relative percentage of `firstColour` with respect to
|
|
`secondColour`.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
# calculate gradient coefficients
|
|
redOffset = float((secondColour.Red() * (100 - percent) / 100) - (firstColour.Red() * percent / 100))
|
|
greenOffset = float((secondColour.Green() * (100 - percent) / 100) - (firstColour.Green() * percent / 100))
|
|
blueOffset = float((secondColour.Blue() * (100 - percent) / 100) - (firstColour.Blue() * percent / 100))
|
|
|
|
return wx.Colour(firstColour.Red() + redOffset, firstColour.Green() + greenOffset,
|
|
firstColour.Blue() + blueOffset)
|
|
|
|
|
|
def RandomColour(self):
|
|
"""
|
|
Creates a random colour.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
r = random.randint(0, 255) # Random value betweem 0-255
|
|
g = random.randint(0, 255) # Random value betweem 0-255
|
|
b = random.randint(0, 255) # Random value betweem 0-255
|
|
|
|
return wx.Colour(r, g, b)
|
|
|
|
|
|
def IsDark(self, colour):
|
|
"""
|
|
Returns whether a colour is dark or light.
|
|
|
|
:param `colour`: an instance of :class:`Colour`.
|
|
|
|
:return: ``True`` if the average RGB values are dark, ``False`` otherwise.
|
|
"""
|
|
|
|
evg = (colour.Red() + colour.Green() + colour.Blue())/3
|
|
|
|
if evg < 127:
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def TruncateText(self, dc, text, maxWidth):
|
|
"""
|
|
Truncates a given string to fit given width size. if the text does not fit
|
|
into the given width it is truncated to fit. The format of the fixed text
|
|
is ``truncate text ...``.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param string `text`: the text to be (eventually) truncated;
|
|
:param integer `maxWidth`: the maximum width allowed for the text.
|
|
|
|
:return: A new string containining the (possibly) truncated text.
|
|
"""
|
|
|
|
textLen = len(text)
|
|
tempText = text
|
|
rectSize = maxWidth
|
|
|
|
fixedText = ""
|
|
|
|
textW, textH = dc.GetTextExtent(text)
|
|
|
|
if rectSize >= textW:
|
|
return text
|
|
|
|
# The text does not fit in the designated area,
|
|
# so we need to truncate it a bit
|
|
suffix = ".."
|
|
w, h = dc.GetTextExtent(suffix)
|
|
rectSize -= w
|
|
|
|
for i in range(textLen, -1, -1):
|
|
|
|
textW, textH = dc.GetTextExtent(tempText)
|
|
if rectSize >= textW:
|
|
fixedText = tempText
|
|
fixedText += ".."
|
|
return fixedText
|
|
|
|
tempText = tempText[:-1]
|
|
|
|
|
|
def DrawButton(self, dc, rect, theme, state, input=None):
|
|
"""
|
|
Colour rectangle according to the theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the rectangle to be filled with gradient shading;
|
|
:param string `theme`: the theme to use to draw the button;
|
|
:param integer `state`: the button state;
|
|
:param `input`: a flag used to call the right method.
|
|
"""
|
|
|
|
if input is None or type(input) == type(False):
|
|
self.DrawButtonTheme(dc, rect, theme, state, input)
|
|
else:
|
|
self.DrawButtonColour(dc, rect, theme, state, input)
|
|
|
|
|
|
def DrawButtonTheme(self, dc, rect, theme, state, useLightColours=True):
|
|
"""
|
|
Draws a button using the appropriate theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the button's client rectangle;
|
|
:param string `theme`: the theme to use to draw the button;
|
|
:param integer `state`: the button state;
|
|
:param bool `useLightColours`: ``True`` to use light colours, ``False`` otherwise.
|
|
"""
|
|
|
|
renderer = self._renderers[theme]
|
|
|
|
# Set background colour if non given by caller
|
|
renderer.DrawButton(dc, rect, state, useLightColours)
|
|
|
|
|
|
def DrawButtonColour(self, dc, rect, theme, state, colour):
|
|
"""
|
|
Draws a button using the appropriate theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the button's client rectangle;
|
|
:param string `theme`: the theme to use to draw the button;
|
|
:param integer `state`: the button state;
|
|
:param `colour`: a valid :class:`Colour` instance.
|
|
"""
|
|
|
|
renderer = self._renderers[theme]
|
|
renderer.DrawButton(dc, rect, state, colour)
|
|
|
|
|
|
def CanMakeWindowsTransparent(self):
|
|
"""
|
|
Used internally.
|
|
|
|
:return: ``True`` if the system supports transparency of toplevel windows,
|
|
otherwise returns ``False``.
|
|
"""
|
|
|
|
if wx.Platform == "__WXMSW__":
|
|
|
|
version = wx.GetOsDescription()
|
|
found = version.find("XP") >= 0 or version.find("2000") >= 0 or version.find("NT") >= 0
|
|
return found
|
|
|
|
elif wx.Platform == "__WXMAC__":
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
# on supported windows systems (Win2000 and greater), this function
|
|
# will make a frame window transparent by a certain amount
|
|
def MakeWindowTransparent(self, wnd, amount):
|
|
"""
|
|
Used internally. Makes a toplevel window transparent if the system supports it.
|
|
|
|
:param `wnd`: the toplevel window to make transparent, an instance of :class:`TopLevelWindow`;
|
|
:param integer `amount`: the window transparency to apply.
|
|
"""
|
|
|
|
if wnd.GetSize() == (0, 0):
|
|
return
|
|
|
|
# this API call is not in all SDKs, only the newer ones, so
|
|
# we will runtime bind this
|
|
if wx.Platform == "__WXMSW__":
|
|
hwnd = wnd.GetHandle()
|
|
|
|
if not hasattr(self, "_winlib"):
|
|
if _libimported == "MH":
|
|
self._winlib = win32api.LoadLibrary("user32")
|
|
elif _libimported == "ctypes":
|
|
self._winlib = ctypes.windll.user32
|
|
|
|
if _libimported == "MH":
|
|
pSetLayeredWindowAttributes = win32api.GetProcAddress(self._winlib,
|
|
"SetLayeredWindowAttributes")
|
|
|
|
if pSetLayeredWindowAttributes == None:
|
|
return
|
|
|
|
exstyle = win32api.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
|
|
if 0 == (exstyle & 0x80000):
|
|
win32api.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, exstyle | 0x80000)
|
|
|
|
winxpgui.SetLayeredWindowAttributes(hwnd, 0, amount, 2)
|
|
|
|
elif _libimported == "ctypes":
|
|
style = self._winlib.GetWindowLongA(hwnd, 0xffffffec)
|
|
style |= 0x00080000
|
|
self._winlib.SetWindowLongA(hwnd, 0xffffffec, style)
|
|
self._winlib.SetLayeredWindowAttributes(hwnd, 0, amount, 2)
|
|
else:
|
|
if not wnd.CanSetTransparent():
|
|
return
|
|
wnd.SetTransparent(amount)
|
|
return
|
|
|
|
|
|
# assumption: the background was already drawn on the dc
|
|
def DrawBitmapShadow(self, dc, rect, where=BottomShadow|RightShadow):
|
|
"""
|
|
Draws a shadow using background bitmap.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the bitmap's client rectangle;
|
|
:param integer `where`: where to draw the shadow. This can be any combination of the
|
|
following bits:
|
|
|
|
========================== ======= ================================
|
|
Shadow Settings Value Description
|
|
========================== ======= ================================
|
|
``RightShadow`` 1 Right side shadow
|
|
``BottomShadow`` 2 Not full bottom shadow
|
|
``BottomShadowFull`` 4 Full bottom shadow
|
|
========================== ======= ================================
|
|
|
|
"""
|
|
|
|
shadowSize = 5
|
|
|
|
# the rect must be at least 5x5 pixles
|
|
if rect.height < 2*shadowSize or rect.width < 2*shadowSize:
|
|
return
|
|
|
|
# Start by drawing the right bottom corner
|
|
if where & BottomShadow or where & BottomShadowFull:
|
|
dc.DrawBitmap(self._rightBottomCorner, rect.x+rect.width, rect.y+rect.height, True)
|
|
|
|
# Draw right side shadow
|
|
xx = rect.x + rect.width
|
|
yy = rect.y + rect.height - shadowSize
|
|
|
|
if where & RightShadow:
|
|
while yy - rect.y > 2*shadowSize:
|
|
dc.DrawBitmap(self._right, xx, yy, True)
|
|
yy -= shadowSize
|
|
|
|
dc.DrawBitmap(self._rightTop, xx, yy - shadowSize, True)
|
|
|
|
if where & BottomShadow:
|
|
xx = rect.x + rect.width - shadowSize
|
|
yy = rect.height + rect.y
|
|
while xx - rect.x > 2*shadowSize:
|
|
dc.DrawBitmap(self._bottom, xx, yy, True)
|
|
xx -= shadowSize
|
|
|
|
dc.DrawBitmap(self._bottomLeft, xx - shadowSize, yy, True)
|
|
|
|
if where & BottomShadowFull:
|
|
xx = rect.x + rect.width - shadowSize
|
|
yy = rect.height + rect.y
|
|
while xx - rect.x >= 0:
|
|
dc.DrawBitmap(self._bottom, xx, yy, True)
|
|
xx -= shadowSize
|
|
|
|
dc.DrawBitmap(self._bottom, xx, yy, True)
|
|
|
|
|
|
def DropShadow(self, wnd, drop=True):
|
|
"""
|
|
Adds a shadow under the window (Windows only).
|
|
|
|
:param `wnd`: the window for which we are dropping a shadow, an instance of :class:`TopLevelWindow`;
|
|
:param bool `drop`: ``True`` to drop a shadow, ``False`` to remove it.
|
|
"""
|
|
|
|
if not self.CanMakeWindowsTransparent() or not _libimported:
|
|
return
|
|
|
|
if "__WXMSW__" in wx.Platform:
|
|
|
|
hwnd = wnd.GetHandle()
|
|
|
|
if not hasattr(self, "_winlib"):
|
|
if _libimported == "MH":
|
|
self._winlib = win32api.LoadLibrary("user32")
|
|
elif _libimported == "ctypes":
|
|
self._winlib = ctypes.windll.user32
|
|
|
|
if _libimported == "MH":
|
|
csstyle = win32api.GetWindowLong(hwnd, win32con.GCL_STYLE)
|
|
else:
|
|
csstyle = self._winlib.GetWindowLongA(hwnd, win32con.GCL_STYLE)
|
|
|
|
if drop:
|
|
if csstyle & CS_DROPSHADOW:
|
|
return
|
|
else:
|
|
csstyle |= CS_DROPSHADOW #Nothing to be done
|
|
|
|
else:
|
|
|
|
if csstyle & CS_DROPSHADOW:
|
|
csstyle &= ~(CS_DROPSHADOW)
|
|
else:
|
|
return #Nothing to be done
|
|
|
|
win32api.SetWindowLong(hwnd, win32con.GCL_STYLE, csstyle)
|
|
|
|
|
|
def GetBitmapStartLocation(self, dc, rect, bitmap, text="", style=0):
|
|
"""
|
|
Returns the top left `x` and `y` cordinates of the bitmap drawing.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the bitmap's client rectangle;
|
|
:param Bitmap `bitmap`: the bitmap associated with the button;
|
|
:param string `text`: the button label;
|
|
:param integer `style`: the button style. This can be one of the following bits:
|
|
|
|
============================== ======= ================================
|
|
Button style Value Description
|
|
============================== ======= ================================
|
|
``BU_EXT_XP_STYLE`` 1 A button with a XP style
|
|
``BU_EXT_2007_STYLE`` 2 A button with a MS Office 2007 style
|
|
``BU_EXT_LEFT_ALIGN_STYLE`` 4 A left-aligned button
|
|
``BU_EXT_CENTER_ALIGN_STYLE`` 8 A center-aligned button
|
|
``BU_EXT_RIGHT_ALIGN_STYLE`` 16 A right-aligned button
|
|
``BU_EXT_RIGHT_TO_LEFT_STYLE`` 32 A button suitable for right-to-left languages
|
|
============================== ======= ================================
|
|
|
|
:return: A tuple containining the top left `x` and `y` cordinates of the bitmap drawing.
|
|
"""
|
|
|
|
alignmentBuffer = self.GetAlignBuffer()
|
|
|
|
# get the startLocationY
|
|
fixedTextWidth = fixedTextHeight = 0
|
|
|
|
if not text:
|
|
fixedTextHeight = bitmap.GetHeight()
|
|
else:
|
|
fixedTextWidth, fixedTextHeight = dc.GetTextExtent(text)
|
|
|
|
startLocationY = rect.y + (rect.height - fixedTextHeight)/2
|
|
|
|
# get the startLocationX
|
|
if style & BU_EXT_RIGHT_TO_LEFT_STYLE:
|
|
|
|
startLocationX = rect.x + rect.width - alignmentBuffer - bitmap.GetWidth()
|
|
|
|
else:
|
|
|
|
if style & BU_EXT_RIGHT_ALIGN_STYLE:
|
|
|
|
maxWidth = rect.x + rect.width - (2 * alignmentBuffer) - bitmap.GetWidth() # the alignment is for both sides
|
|
|
|
# get the truncated text. The text may stay as is, it is not a must that is will be trancated
|
|
fixedText = self.TruncateText(dc, text, maxWidth)
|
|
|
|
# get the fixed text dimentions
|
|
fixedTextWidth, fixedTextHeight = dc.GetTextExtent(fixedText)
|
|
|
|
# calculate the start location
|
|
startLocationX = maxWidth - fixedTextWidth
|
|
|
|
elif style & BU_EXT_LEFT_ALIGN_STYLE:
|
|
|
|
# calculate the start location
|
|
startLocationX = alignmentBuffer
|
|
|
|
else: # meaning BU_EXT_CENTER_ALIGN_STYLE
|
|
|
|
maxWidth = rect.x + rect.width - (2 * alignmentBuffer) - bitmap.GetWidth() # the alignment is for both sides
|
|
|
|
# get the truncated text. The text may stay as is, it is not a must that is will be trancated
|
|
fixedText = self.TruncateText(dc, text, maxWidth)
|
|
|
|
# get the fixed text dimentions
|
|
fixedTextWidth, fixedTextHeight = dc.GetTextExtent(fixedText)
|
|
|
|
if maxWidth > fixedTextWidth:
|
|
|
|
# calculate the start location
|
|
startLocationX = (maxWidth - fixedTextWidth) / 2
|
|
|
|
else:
|
|
|
|
# calculate the start location
|
|
startLocationX = maxWidth - fixedTextWidth
|
|
|
|
# it is very important to validate that the start location is not less than the alignment buffer
|
|
if startLocationX < alignmentBuffer:
|
|
startLocationX = alignmentBuffer
|
|
|
|
return startLocationX, startLocationY
|
|
|
|
|
|
def GetTextStartLocation(self, dc, rect, bitmap, text, style=0):
|
|
"""
|
|
Returns the top left `x` and `y` cordinates of the text drawing.
|
|
In case the text is too long, the text is being fixed (the text is cut and
|
|
a '...' mark is added in the end).
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the text's client rectangle;
|
|
:param Bitmap `bitmap`: the bitmap associated with the button;
|
|
:param string `text`: the button label;
|
|
:param integer `style`: the button style.
|
|
|
|
:return: A tuple containining the top left `x` and `y` cordinates of the text drawing, plus
|
|
the truncated version of the input `text`.
|
|
|
|
:see: :meth:`~ArtManager.GetBitmapStartLocation` for a list of valid button styles.
|
|
"""
|
|
|
|
alignmentBuffer = self.GetAlignBuffer()
|
|
|
|
# get the bitmap offset
|
|
bitmapOffset = 0
|
|
if bitmap != wx.NullBitmap:
|
|
bitmapOffset = bitmap.GetWidth()
|
|
|
|
# get the truncated text. The text may stay as is, it is not a must that is will be trancated
|
|
maxWidth = rect.x + rect.width - (2 * alignmentBuffer) - bitmapOffset # the alignment is for both sides
|
|
|
|
fixedText = self.TruncateText(dc, text, maxWidth)
|
|
|
|
# get the fixed text dimentions
|
|
fixedTextWidth, fixedTextHeight = dc.GetTextExtent(fixedText)
|
|
startLocationY = (rect.height - fixedTextHeight) / 2 + rect.y
|
|
|
|
# get the startLocationX
|
|
if style & BU_EXT_RIGHT_TO_LEFT_STYLE:
|
|
|
|
startLocationX = maxWidth - fixedTextWidth + alignmentBuffer
|
|
|
|
else:
|
|
|
|
if style & BU_EXT_LEFT_ALIGN_STYLE:
|
|
|
|
# calculate the start location
|
|
startLocationX = bitmapOffset + alignmentBuffer
|
|
|
|
elif style & BU_EXT_RIGHT_ALIGN_STYLE:
|
|
|
|
# calculate the start location
|
|
startLocationX = maxWidth - fixedTextWidth + bitmapOffset + alignmentBuffer
|
|
|
|
else: # meaning wxBU_EXT_CENTER_ALIGN_STYLE
|
|
|
|
# calculate the start location
|
|
startLocationX = (maxWidth - fixedTextWidth) / 2 + bitmapOffset + alignmentBuffer
|
|
|
|
|
|
# it is very important to validate that the start location is not less than the alignment buffer
|
|
if startLocationX < alignmentBuffer:
|
|
startLocationX = alignmentBuffer
|
|
|
|
return startLocationX, startLocationY, fixedText
|
|
|
|
|
|
def DrawTextAndBitmap(self, dc, rect, text, enable=True, font=wx.NullFont,
|
|
fontColour=wx.BLACK, bitmap=wx.NullBitmap,
|
|
grayBitmap=wx.NullBitmap, style=0):
|
|
"""
|
|
Draws the text & bitmap on the input dc.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the text and bitmap client rectangle;
|
|
:param string `text`: the button label;
|
|
:param bool `enable`: ``True`` if the button is enabled, ``False`` otherwise;
|
|
:param `font`: the font to use to draw the text, an instance of :class:`Font`;
|
|
:param `fontColour`: the colour to use to draw the text, an instance of
|
|
:class:`Colour`;
|
|
:param `bitmap`: the bitmap associated with the button, an instance of :class:`Bitmap`;
|
|
:param `grayBitmap`: a greyed-out version of the input `bitmap` representing
|
|
a disabled bitmap, an instance of :class:`Bitmap`;
|
|
:param integer `style`: the button style.
|
|
|
|
:see: :meth:`~ArtManager.GetBitmapStartLocation` for a list of valid button styles.
|
|
"""
|
|
|
|
# enable colours
|
|
if enable:
|
|
dc.SetTextForeground(fontColour)
|
|
else:
|
|
dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
|
|
|
|
# set the font
|
|
|
|
if font == wx.NullFont:
|
|
font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
|
|
|
|
dc.SetFont(font)
|
|
|
|
startLocationX = startLocationY = 0
|
|
|
|
if bitmap != wx.NullBitmap:
|
|
|
|
# calculate the bitmap start location
|
|
startLocationX, startLocationY = self.GetBitmapStartLocation(dc, rect, bitmap, text, style)
|
|
|
|
# draw the bitmap
|
|
if enable:
|
|
dc.DrawBitmap(bitmap, startLocationX, startLocationY, True)
|
|
else:
|
|
dc.DrawBitmap(grayBitmap, startLocationX, startLocationY, True)
|
|
|
|
# calculate the text start location
|
|
location, labelOnly = self.GetAccelIndex(text)
|
|
startLocationX, startLocationY, fixedText = self.GetTextStartLocation(dc, rect, bitmap, labelOnly, style)
|
|
|
|
# after all the caculations are finished, it is time to draw the text
|
|
# underline the first letter that is marked with a '&'
|
|
if location == -1 or font.GetUnderlined() or location >= len(fixedText):
|
|
# draw the text
|
|
dc.DrawText(fixedText, startLocationX, startLocationY)
|
|
|
|
else:
|
|
|
|
# underline the first '&'
|
|
before = fixedText[0:location]
|
|
underlineLetter = fixedText[location]
|
|
after = fixedText[location+1:]
|
|
|
|
# before
|
|
dc.DrawText(before, startLocationX, startLocationY)
|
|
|
|
# underlineLetter
|
|
if "__WXGTK__" not in wx.Platform:
|
|
w1, h = dc.GetTextExtent(before)
|
|
font.SetUnderlined(True)
|
|
dc.SetFont(font)
|
|
dc.DrawText(underlineLetter, startLocationX + w1, startLocationY)
|
|
else:
|
|
w1, h = dc.GetTextExtent(before)
|
|
dc.DrawText(underlineLetter, startLocationX + w1, startLocationY)
|
|
|
|
# Draw the underline ourselves since using the Underline in GTK,
|
|
# causes the line to be too close to the letter
|
|
uderlineLetterW, uderlineLetterH = dc.GetTextExtent(underlineLetter)
|
|
|
|
curPen = dc.GetPen()
|
|
dc.SetPen(wx.BLACK_PEN)
|
|
|
|
dc.DrawLine(startLocationX + w1, startLocationY + uderlineLetterH - 2,
|
|
startLocationX + w1 + uderlineLetterW, startLocationY + uderlineLetterH - 2)
|
|
dc.SetPen(curPen)
|
|
|
|
# after
|
|
w2, h = dc.GetTextExtent(underlineLetter)
|
|
font.SetUnderlined(False)
|
|
dc.SetFont(font)
|
|
dc.DrawText(after, startLocationX + w1 + w2, startLocationY)
|
|
|
|
|
|
def CalcButtonBestSize(self, label, bmp):
|
|
"""
|
|
Returns the best fit size for the supplied label & bitmap.
|
|
|
|
:param string `label`: the button label;
|
|
:param `bmp`: the bitmap associated with the button, an instance of :class:`Bitmap`.
|
|
|
|
:return: An instance of :class:`Size`, representing the best fit size for the supplied label & bitmap.
|
|
"""
|
|
|
|
if "__WXMSW__" in wx.Platform:
|
|
HEIGHT = 22
|
|
else:
|
|
HEIGHT = 26
|
|
|
|
dc = wx.MemoryDC()
|
|
dc.SelectBitmap(wx.Bitmap(1, 1))
|
|
|
|
dc.SetFont(wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT))
|
|
width, height, dummy = dc.GetFullMultiLineTextExtent(label)
|
|
|
|
width += 2*self.GetAlignBuffer()
|
|
|
|
if bmp.IsOk():
|
|
|
|
# allocate extra space for the bitmap
|
|
heightBmp = bmp.GetHeight() + 2
|
|
if height < heightBmp:
|
|
height = heightBmp
|
|
|
|
width += bmp.GetWidth() + 2
|
|
|
|
if height < HEIGHT:
|
|
height = HEIGHT
|
|
|
|
dc.SelectBitmap(wx.NullBitmap)
|
|
|
|
return wx.Size(width, height)
|
|
|
|
|
|
def GetMenuFaceColour(self):
|
|
"""
|
|
Returns the colour used for the menu foreground.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
renderer = self._renderers[self.GetMenuTheme()]
|
|
return renderer.GetMenuFaceColour()
|
|
|
|
|
|
def GetTextColourEnable(self):
|
|
"""
|
|
Returns the colour used for enabled menu items.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
renderer = self._renderers[self.GetMenuTheme()]
|
|
return renderer.GetTextColourEnable()
|
|
|
|
|
|
def GetTextColourDisable(self):
|
|
"""
|
|
Returns the colour used for disabled menu items.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
renderer = self._renderers[self.GetMenuTheme()]
|
|
return renderer.GetTextColourDisable()
|
|
|
|
|
|
def GetFont(self):
|
|
"""
|
|
Returns the font used by this theme.
|
|
|
|
:return: An instance of :class:`Font`.
|
|
"""
|
|
|
|
renderer = self._renderers[self.GetMenuTheme()]
|
|
return renderer.GetFont()
|
|
|
|
|
|
def GetAccelIndex(self, label):
|
|
"""
|
|
Returns the mnemonic index of the label and the label stripped of the ampersand mnemonic
|
|
(e.g. 'lab&el' ==> will result in 3 and labelOnly = label).
|
|
|
|
:param string `label`: a string containining an ampersand.
|
|
|
|
:return: A tuple containining the mnemonic index of the label and the label
|
|
stripped of the ampersand mnemonic.
|
|
"""
|
|
|
|
indexAccel = 0
|
|
while True:
|
|
indexAccel = label.find("&", indexAccel)
|
|
if indexAccel == -1:
|
|
return indexAccel, label
|
|
if label[indexAccel:indexAccel+2] == "&&":
|
|
label = label[0:indexAccel] + label[indexAccel+1:]
|
|
indexAccel += 1
|
|
else:
|
|
break
|
|
|
|
labelOnly = label[0:indexAccel] + label[indexAccel+1:]
|
|
|
|
return indexAccel, labelOnly
|
|
|
|
|
|
def GetThemeBaseColour(self, useLightColours=True):
|
|
"""
|
|
Returns the theme (Blue, Silver, Green etc.) base colour, if no theme is active
|
|
it return the active caption colour, lighter in 30%.
|
|
|
|
:param bool `useLightColours`: ``True`` to use light colours, ``False`` otherwise.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
if not useLightColours and not self.IsDark(self.FrameColour()):
|
|
return wx.Colour("GOLD")
|
|
else:
|
|
return self.LightColour(self.FrameColour(), 30)
|
|
|
|
|
|
def GetAlignBuffer(self):
|
|
"""
|
|
Return the padding buffer for a text or bitmap.
|
|
|
|
:return: An integer representing the padding buffer.
|
|
"""
|
|
|
|
return self._alignmentBuffer
|
|
|
|
|
|
def SetMenuTheme(self, theme):
|
|
"""
|
|
Set the menu theme, possible values (Style2007, StyleXP, StyleVista).
|
|
|
|
:param string `theme`: a rendering theme class, either `StyleXP`, `Style2007` or `StyleVista`.
|
|
"""
|
|
|
|
self._menuTheme = theme
|
|
|
|
|
|
def GetMenuTheme(self):
|
|
"""
|
|
Returns the currently used menu theme.
|
|
|
|
:return: A string containining the currently used theme for the menu.
|
|
"""
|
|
|
|
return self._menuTheme
|
|
|
|
|
|
def AddMenuTheme(self, render):
|
|
"""
|
|
Adds a new theme to the stock.
|
|
|
|
:param `render`: a rendering theme class, which must be derived from
|
|
:class:`RendererBase`.
|
|
|
|
:return: An integer representing the size of the renderers dictionary.
|
|
"""
|
|
|
|
# Add new theme
|
|
lastRenderer = len(self._renderers)
|
|
self._renderers[lastRenderer] = render
|
|
|
|
return lastRenderer
|
|
|
|
|
|
def SetMS2007ButtonSunken(self, sunken):
|
|
"""
|
|
Sets MS 2007 button style sunken or not.
|
|
|
|
:param bool `sunken`: ``True`` to have a sunken border effect, ``False`` otherwise.
|
|
"""
|
|
|
|
self._ms2007sunken = sunken
|
|
|
|
|
|
def GetMS2007ButtonSunken(self):
|
|
"""
|
|
Returns the sunken flag for MS 2007 buttons.
|
|
|
|
:return: ``True`` if the MS 2007 buttons are sunken, ``False`` otherwise.
|
|
"""
|
|
|
|
return self._ms2007sunken
|
|
|
|
|
|
def GetMBVerticalGradient(self):
|
|
""" Returns ``True`` if the menu bar should be painted with vertical gradient. """
|
|
|
|
return self._verticalGradient
|
|
|
|
|
|
def SetMBVerticalGradient(self, v):
|
|
"""
|
|
Sets the menu bar gradient style.
|
|
|
|
:param bool `v`: ``True`` for a vertical shaded gradient, ``False`` otherwise.
|
|
"""
|
|
|
|
self._verticalGradient = v
|
|
|
|
|
|
def DrawMenuBarBorder(self, border):
|
|
"""
|
|
Enables menu border drawing (XP style only).
|
|
|
|
:param bool `border`: ``True`` to draw the menubar border, ``False`` otherwise.
|
|
"""
|
|
|
|
self._drowMBBorder = border
|
|
|
|
|
|
def GetMenuBarBorder(self):
|
|
"""
|
|
Returns menu bar border drawing flag.
|
|
|
|
:return: ``True`` if the menu bar border is to be drawn, ``False`` otherwise.
|
|
"""
|
|
|
|
return self._drowMBBorder
|
|
|
|
|
|
def GetMenuBgFactor(self):
|
|
"""
|
|
Gets the visibility depth of the menu in Metallic style.
|
|
The higher the value, the menu bar will look more raised
|
|
"""
|
|
|
|
return self._menuBgFactor
|
|
|
|
|
|
def DrawDragSash(self, rect):
|
|
"""
|
|
Draws resize sash.
|
|
|
|
:param Rect `rect`: the sash client rectangle.
|
|
"""
|
|
|
|
dc = wx.ScreenDC()
|
|
mem_dc = wx.MemoryDC()
|
|
|
|
bmp = wx.Bitmap(rect.width, rect.height)
|
|
mem_dc.SelectObject(bmp)
|
|
mem_dc.SetBrush(wx.WHITE_BRUSH)
|
|
mem_dc.SetPen(wx.Pen(wx.WHITE, 1))
|
|
mem_dc.DrawRectangle(0, 0, rect.width, rect.height)
|
|
|
|
dc.Blit(rect.x, rect.y, rect.width, rect.height, mem_dc, 0, 0, wx.XOR)
|
|
|
|
|
|
def TakeScreenShot(self, rect, bmp):
|
|
"""
|
|
Takes a screenshot of the screen at given position & size (rect).
|
|
|
|
:param Rect `rect`: the screen rectangle we wish to capture;
|
|
:param Bitmap `bmp`: currently unused.
|
|
"""
|
|
|
|
# Create a DC for the whole screen area
|
|
dcScreen = wx.ScreenDC()
|
|
|
|
# Create a Bitmap that will later on hold the screenshot image
|
|
# Note that the Bitmap must have a size big enough to hold the screenshot
|
|
# -1 means using the current default colour depth
|
|
bmp = wx.Bitmap(rect.width, rect.height)
|
|
|
|
# Create a memory DC that will be used for actually taking the screenshot
|
|
memDC = wx.MemoryDC()
|
|
|
|
# Tell the memory DC to use our Bitmap
|
|
# all drawing action on the memory DC will go to the Bitmap now
|
|
memDC.SelectObject(bmp)
|
|
|
|
# Blit (in this case copy) the actual screen on the memory DC
|
|
# and thus the Bitmap
|
|
memDC.Blit( 0, # Copy to this X coordinate
|
|
0, # Copy to this Y coordinate
|
|
rect.width, # Copy this width
|
|
rect.height, # Copy this height
|
|
dcScreen, # From where do we copy?
|
|
rect.x, # What's the X offset in the original DC?
|
|
rect.y # What's the Y offset in the original DC?
|
|
)
|
|
|
|
# Select the Bitmap out of the memory DC by selecting a new
|
|
# uninitialized Bitmap
|
|
memDC.SelectObject(wx.NullBitmap)
|
|
|
|
|
|
def DrawToolBarBg(self, dc, rect):
|
|
"""
|
|
Draws the toolbar background according to the active theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the toolbar's client rectangle.
|
|
"""
|
|
|
|
renderer = self._renderers[self.GetMenuTheme()]
|
|
|
|
# Set background colour if non given by caller
|
|
renderer.DrawToolBarBg(dc, rect)
|
|
|
|
|
|
def DrawMenuBarBg(self, dc, rect):
|
|
"""
|
|
Draws the menu bar background according to the active theme.
|
|
|
|
:param `dc`: an instance of :class:`DC`;
|
|
:param Rect `rect`: the menubar's client rectangle.
|
|
"""
|
|
|
|
renderer = self._renderers[self.GetMenuTheme()]
|
|
# Set background colour if non given by caller
|
|
renderer.DrawMenuBarBg(dc, rect)
|
|
|
|
|
|
def SetMenuBarColour(self, scheme):
|
|
"""
|
|
Sets the menu bar colour scheme to use.
|
|
|
|
:param string `scheme`: a string representing a colour scheme (i.e., 'Default',
|
|
'Dark', 'Dark Olive Green', 'Generic').
|
|
"""
|
|
|
|
self._menuBarColourScheme = scheme
|
|
# set default colour
|
|
if scheme in self._colourSchemeMap:
|
|
self._menuBarBgColour = self._colourSchemeMap[scheme]
|
|
|
|
|
|
def GetMenuBarColourScheme(self):
|
|
"""
|
|
Returns the current colour scheme.
|
|
|
|
:return: A string representing the current colour scheme.
|
|
"""
|
|
|
|
return self._menuBarColourScheme
|
|
|
|
|
|
def GetMenuBarFaceColour(self):
|
|
"""
|
|
Returns the menu bar face colour.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return self._menuBarBgColour
|
|
|
|
|
|
def GetMenuBarSelectionColour(self):
|
|
"""
|
|
Returns the menu bar selection colour.
|
|
|
|
:return: An instance of :class:`Colour`.
|
|
"""
|
|
|
|
return self._menuBarSelColour
|
|
|
|
|
|
def InitColours(self):
|
|
""" Initialise the colour map. """
|
|
|
|
self._colourSchemeMap = {_("Default"): wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE),
|
|
_("Dark"): wx.BLACK,
|
|
_("Dark Olive Green"): wx.Colour("DARK OLIVE GREEN"),
|
|
_("Generic"): wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVECAPTION)}
|
|
|
|
|
|
def GetColourSchemes(self):
|
|
"""
|
|
Returns the available colour schemes.
|
|
|
|
:return: A list of strings representing the available colour schemes.
|
|
"""
|
|
|
|
return list(self._colourSchemeMap.keys())
|
|
|
|
|
|
def CreateGreyBitmap(self, bmp):
|
|
"""
|
|
Creates a grey bitmap image from the input bitmap.
|
|
|
|
:param `bmp`: a valid :class:`Bitmap` object to be greyed out.
|
|
|
|
:return: A greyed-out representation of the input bitmap, an instance of :class:`Bitmap`.
|
|
"""
|
|
|
|
img = bmp.ConvertToImage()
|
|
return wx.Bitmap(img.ConvertToGreyscale())
|
|
|
|
|
|
def GetRaiseToolbar(self):
|
|
""" Returns ``True`` if we are dropping a shadow under a toolbar. """
|
|
|
|
return self._raiseTB
|
|
|
|
|
|
def SetRaiseToolbar(self, rais):
|
|
"""
|
|
Enables/disables toobar shadow drop.
|
|
|
|
:param bool `rais`: ``True`` to drop a shadow below a toolbar, ``False`` otherwise.
|
|
"""
|
|
|
|
self._raiseTB = rais
|
|
|
|
|