• Facebook
  • Twitter
  • Reddit
  • StumbleUpon
  • Digg
  • email

# --------------------------------------------------------------------------------- #
# FLATMENU wxPython IMPLEMENTATION
#
# Andrea Gavana, @ 03 Nov 2006
# Latest Revision: 16 Apr 2007, 20.00 CET
#
#
# TODO List
#
# 1. Work is still in progress, so other functionalities may be added in the future;
# 2. No shadows under MAC, but it may be possible to create them using Carbon.
#
#
# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
# Write To Me At:
#
# gavana@kpo.kz
# andrea.gavana@gmail.com
#
# Or, Obviously, To The wxPython Mailing List!!!
#
#
# End Of Comments
# --------------------------------------------------------------------------------- #
 
"""
Description
===========
 
FlatMenu, like the name implies, it is a generic menu implementation. 
I tried to provide a full functionality for menus, menubar and toolbar.
FlatMenu includes everything that regular menu bar has except two known
missing functionalities that will be completed ASAP:
 
- No scrolling is available if the menu height is greater than the screen height 
 
 
FlatMenu supports the following features:
 
  - Fires all the events (UI & Cmd);
  - Check items;
  - Separators;
  - Enabled / Disabled menu items;
  - Images on items;
  - Toolbar support, with images and separators;
  - Controls in toolbar (work in progress);
  - Toolbar tools tooltips (done: thanks to Peter Kort);
  - Accelerators for menus;
  - Accelerators for menubar;
  - Radio items in menus;
  - Integration with AUI;
  - Scrolling when menu is too big to fit the screen (in progress);
  - Menu navigation with keyboard;
  - Drop down arrow button to the right of the menu, it always contains the
    "Customize" option, which will popup an options dialog. The dialog has the
    following abilities:
      (a) Ability to add/remove menus;
      (b) Select different colour schemes for the menu bar / toolbar;
      (c) Control various options, such as: colour for highlight menu item, draw
          border around menus (classic look only);
      (d) Toolbar floating appearance.
  - Allows user to specify grey bitmap for disabled menus/toolbar tools;
  - If no grey bitmap is provided, it generates one from the existing bitmap;
  - Hidden toolbar items / menu bar items - will appear in a small popmenu
    to the right if they are hidden;
  - 4 different colour schemes for the menu bar (more can easily added).
 
 
Events
======
 
FlatMenu implements this event for menus and toolbar tools:
 
  - EVT_FLAT_MENU_SELECTED
 
 
Supported Platforms
===================
 
FlatMenu has been tested on the following platforms:
  * Windows (Windows XP);
  * Linux Ubuntu (Dapper 6.06)
 
 
License And Version:
===================
 
FlatMenu is freeware and distributed under the wxPython license. 
 
 
Latest Revision: Andrea Gavana @ 16 Apr 2007, 20.00 CET
Version 0.3
 
"""
 
__docformat__ = "epytext"
 
 
import wx
 
from FMCustomizeDlg import FMCustomizeDlg
from ArtManager import ArtManager, DCSaver
from Resources import *
 
 
# Some checking to see if we can draw shadows behind the popup menus
# at least on Windows. *REQUIRES* Mark Hammond's win32all extensions
# and ctypes, on Windows obviouly. Mac and GTK have no shadows under
# the menus, and it has been reported that shadows don't work well
# on Windows 2000 and previous.
 
_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
            import win32gui
            _libimported = "MH"
        except:
            try:
                import ctypes
                _libimported = "ctypes"
            except:
                pass
    else:
        _libimported = None
 
# Simple hack, but I don't know how to make it work on Mac
# I don't have  Mac ;-)
if wx.Platform == "__WXMAC__":
    try:
        import ctypes
        _carbon_dll = ctypes.cdll.LoadLibrary(r'/System/Frameworks/Carbon.framework/Carbon')
    except:
        _carbon_dll = None
 
 
# FIXME: No way to get shadows on Windows with the original code...
# May anyone share some suggestion on how to make it work??
# Right now I am using win32api to create shadows behind wx.PopupWindow,
# but this will result in *all* the popup windows in an application
# to have shadows behind them, even the user defined wx.PopupWindow
# that do not derive from FlatMenu.
 
if wx.VERSION >= (2,7,0,0):
    import wx.aui as AUI
    _hasAUI = True
else:
    try:
        import PyAUI as AUI
        _hasAUI = True
    except:
        _hasAUI = False
 
# Check for the new method in 2.7 (not present in 2.6.3.3)
if wx.VERSION_STRING < "2.7":
    wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point)
 
 
wxEVT_FLAT_MENU_DISMISSED = wx.NewEventType()
wxEVT_FLAT_MENU_SELECTED = wx.wxEVT_COMMAND_MENU_SELECTED
 
EVT_FLAT_MENU_DISMISSED = wx.PyEventBinder(wxEVT_FLAT_MENU_DISMISSED, 1)
""" Used internally. """
EVT_FLAT_MENU_SELECTED = wx.PyEventBinder(wxEVT_FLAT_MENU_SELECTED, 2)
""" Fires the wx.EVT_MENU event for FlatMenu. """
 
 
def MSWGetCreateWindowCoords(pos, size):
    """ Creates window coordinates for MS platforms. """
 
    # yes, those are just some arbitrary hardcoded numbers
    DEFAULT_Y = 200
 
    nonDefault = False
 
    if pos.x == -1:
 
        # if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
        # can just as well set it to CW_USEDEFAULT as well
        x = 0
        y = win32con.CW_USEDEFAULT
 
    else:
 
        # OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
        # neither because it is not handled as a special value by Windows then
        # and so we have to choose some default value for it
        x = pos.x
        y = (pos.y == -1 and [DEFAULT_Y] or [pos.y])[0]
 
        nonDefault = True
 
    if size.x == -1 or size.y == -1:
        nonDefault = True
 
    w = WidthDefault(size.x)
    h = HeightDefault(size.y)
 
    return x, y, w, h
 
 
def WidthDefault(w):
    """ Used internally. """
 
    return (w == -1 and [20] or [w])[0]
 
 
def HeightDefault(h):
    """ Used internally. """
 
    return (h == -1 and [20] or [h])[0]
 
 
def ConvertToMonochrome(bmp):
    """ Converts a bitmap to monochrome colour. """
 
    mem_dc = wx.MemoryDC()
    shadow = wx.EmptyBitmap(bmp.GetWidth(), bmp.GetHeight())
    mem_dc.SelectObject(shadow)
    mem_dc.DrawBitmap(bmp, 0, 0, True)
    mem_dc.SelectObject(wx.NullBitmap)
    img = shadow.ConvertToImage()
    img = img.ConvertToMono(0, 0, 0)
 
    # we now have black where the original bmp was drawn,
    # white elsewhere
    shadow = wx.BitmapFromImage(img)
    shadow.SetMask(wx.Mask(shadow, wx.BLACK))
 
    # Convert the black to grey
    tmp = wx.EmptyBitmap(bmp.GetWidth(), bmp.GetHeight())
    col = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
    mem_dc.SelectObject(tmp)
    mem_dc.SetPen(wx.Pen(col))
    mem_dc.SetBrush(wx.Brush(col))
    mem_dc.DrawRectangle(0, 0, bmp.GetWidth(), bmp.GetHeight())
    mem_dc.DrawBitmap(shadow, 0, 0, True)   # now contains a bitmap with grey where the image was, white elsewhere
    mem_dc.SelectObject(wx.NullBitmap)
    shadow = tmp
    shadow.SetMask(wx.Mask(shadow, wx.WHITE)) 
 
    return shadow
 
 
# ---------------------------------------------------------------------------- #
# Class FlatMenuEvent
# ---------------------------------------------------------------------------- #
 
class FlatMenuEvent(wx.PyCommandEvent):
    """
    Event class that supports the FlatMenu-compatible event called
    EVT_FLAT_MENU_SELECTED.
    """
 
    def __init__(self, eventType, id=1, nSel=-1, nOldSel=-1):
        """ Default class constructor. """
 
        wx.PyCommandEvent.__init__(self, eventType, id)
        self._eventType = eventType
 
 
# ---------------------------------------------------------------------------- #
# Class MenuEntryInfo
# ---------------------------------------------------------------------------- #
 
class MenuEntryInfo:
    """
    Internal class which holds information about a menu.
    """
 
    def __init__(self, titleOrMenu="", menu=None, state=ControlNormal, cmd=wx.ID_ANY):
        """ Default class constructor. """
 
        if type(titleOrMenu) == type(""):
 
            self._title = titleOrMenu
            self._menu = menu
 
            self._rect = wx.Rect()
            self._state = state
            if cmd == wx.ID_ANY:
                cmd = wx.NewId()
 
            self._cmd = cmd             # the menu itself accelerator id
 
        else:
 
            self._title = titleOrMenu._title
            self._menu = titleOrMenu._menu
            self._rect = titleOrMenu._rect
            self._state = titleOrMenu._state
            self._cmd = titleOrMenu._cmd
 
        self._textBmp = wx.NullBitmap
 
 
    def GetTitle(self):
        """ Returns the class title. """
 
        return self._title 
 
 
    def GetMenu(self):
        """ Returns the class menu. """
 
        return self._menu 
 
 
    def SetRect(self, rect):
        """ Sets the class rect. """
 
        self._rect = rect
 
 
    def GetRect(self):
        """ Returns the class rect. """
 
        return self._rect
 
 
    def SetState(self, state):
        """ Sets the class state. """
 
        self._state = state
 
 
    def GetState(self):
        """ Returns the class state. """
 
        return self._state
 
 
    def SetTextBitmap(self, bmp) :
        """ Sets the class bitmap. """
 
        self._textBmp = bmp
 
 
    def GetTextBitmap(self):
        """ Returns the class bitmap. """
 
        return self._textBmp
 
 
    def GetCmdId(self):
        """ Returns the associated command ID. """
 
        return self._cmd
 
 
# ---------------------------------------------------------------------------- #
# Class FlatMenuBar
# ---------------------------------------------------------------------------- #
 
class FlatMenuBar(wx.Panel):
    """
    Implements the generic owner-drawn menu bar for FlatMenu.
    """
 
    def __init__(self, parent, id=wx.ID_ANY, showToolbar=False, iconSize=SmallIcons):
        """
        Default class constructor.
 
        Parameters:
        @param parent menu bar parent
        @param id: window id
        @param showToolbar: True if you want to show FlatToolbar, False otherwise
        @param iconSize: size of the icons in the toolbar (see Resources.py)
        """        
 
        self._curretHiliteItem = -1
 
        self._items = []
        self._dropDownButtonArea = wx.Rect()
        self._showToolbar = showToolbar
        self._tbIconSize = iconSize
        self._tbButtons = []
        self._interval = 20      # 20 milliseconds
        self._showTooltip = -1
 
        self._dropDownButtonState = ControlNormal
        self._moreMenu = None
        self._dlg = None
        self._tbMenu = None
 
        mem_dc = wx.MemoryDC()
        mem_dc.SelectObject(wx.EmptyBitmap(1, 1))
        dummy, self._barHeight = mem_dc.GetTextExtent("Tp")
        mem_dc.SelectObject(wx.NullBitmap)
 
        self._barHeight += 4*SPACER
        if self._showToolbar:
            # add the toolbar height to the menubar height
            self._barHeight += self._tbIconSize + SPACER
 
        wx.Panel.__init__(self, parent, id, size=(-1, self._barHeight), style=wx.WANTS_CHARS)
 
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBg)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_MOTION, self.OnMouseMove)
        self.Bind(EVT_FLAT_MENU_DISMISSED, self.OnMenuDismissed)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
        self.Bind(wx.EVT_IDLE, self.OnIdle)
 
        if "__WXGTK__" in wx.Platform:
            self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
 
        self.SetFocus()
 
        # start the stop watch
        self._watch = wx.StopWatch()
        self._watch.Start()
 
 
    def Append(self, menu, title):
        """ Adds the item to the end of the menu bar. """
 
        menu._menuBarFullTitle = title
        position, label = ArtManager.Get().GetAccelIndex(title)
        menu._menuBarLabelOnly = label
 
        return self.Insert(len(self._items), menu, title)
 
 
    def OnIdle(self, event):
        """ Handles the wx.EVT_IDLE event for FlatMenuBar. """
 
        refresh = False
 
        if self._watch.Time() > self._interval:
 
            # it is time to process UpdateUIEvents
            for but in self._tbButtons:
                event = wx.UpdateUIEvent(but._tbItem.GetId())
                event.Enable(but._tbItem.IsEnabled())
                event.SetText(but._tbItem.GetLabel())
                event.SetEventObject(self)
 
                self.GetEventHandler().ProcessEvent(event)
 
                if but._tbItem.GetLabel() != event.GetText() or but._tbItem.IsEnabled() != event.GetEnabled():
                    refresh = True
 
                but._tbItem.SetLabel(event.GetText())
                but._tbItem.Enable(event.GetEnabled())
 
            self._watch.Start() # Reset the timer
 
        # we need to update the menu bar
        if refresh:
            self.Refresh()
 
 
    def UpdateItem(self, item):
        """
        An item with ID was modified. This function is called by FlatMenu in case
        an item was modified directly and not via updateUI event.
        """
 
        if not self._showToolbar:
            return
 
        # search for a tool bar with id
        refresh = False
 
        for but in self._tbButtons:
            if but._tbItem.GetId() == item.GetId():
                if but._tbItem.IsEnabled() != item.IsEnabled():
                    refresh = True
 
                but._tbItem.Enable(item.IsEnabled())
                break
 
        if refresh:        
            self.Refresh()
 
 
    def OnPaint(self, event):
        """ Handles the wx.EVT_PAINT event for FlatMenuBar. """
 
        # on GTK, dont use the bitmap for drawing, 
        # draw directly on the DC
 
        if "__WXGTK__" in wx.Platform:
            self.ClearBitmaps(0)
 
        dc = wx.BufferedPaintDC(self)
        fnt = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
        dc.SetFont(fnt)
 
        clientRect = self.GetClientRect()
        ArtManager.Get().DrawMenuBarBg(dc, clientRect)
 
        # Get a backgroud image of the more menu button
        moreMenubtnBgBmpRect = wx.Rect(*self.GetMoreMenuButtonRect())
 
        self._moreMenuBgBmp = wx.EmptyBitmap(moreMenubtnBgBmpRect.width, moreMenubtnBgBmpRect.height)
        memDc = wx.MemoryDC()
        memDc.SelectObject(self._moreMenuBgBmp)
        memDc.Blit(0, 0, self._moreMenuBgBmp.GetWidth(), self._moreMenuBgBmp.GetHeight(), dc,
                   moreMenubtnBgBmpRect.x, moreMenubtnBgBmpRect.y)
        memDc.SelectObject(wx.NullBitmap)
 
        padding, dummy = dc.GetTextExtent("W")
        barHeight = self._barHeight
 
        posx = SPACER
        posy = 2*SPACER
 
        # ---------------------------------------------------------------------------
        # Draw as much items as we can if the screen is not wide enough, add all
        # missing items to a drop down menu
        # ---------------------------------------------------------------------------
        menuBarRect = self.GetClientRect()
 
        # Draw the drop down arrow button
        self.DrawMoreButton(dc, 0, self._dropDownButtonState)
 
        # Set the button rect
        self._dropDownButtonArea = moreMenubtnBgBmpRect
 
        # mark all items as non-visibles at first
        for item in self._items:
            item.SetRect(wx.Rect())
 
        for item in self._items:
 
            # Handle accelerator ('&')        
            title = item.GetTitle()
 
            fixedText = title
            location, labelOnly = ArtManager.Get().GetAccelIndex(fixedText)
 
            # Get the menu item length, add some padding to it
            textWidth, textHeight = dc.GetTextExtent(fixedText)
            rect = wx.Rect(posx, posy, textWidth + SPACER + padding, textHeight)
 
            # Can we draw more??
            # the +DROP_DOWN_ARROW_WIDTH  is the width of the drop down arrow
            if posx + rect.width + DROP_DOWN_ARROW_WIDTH >= menuBarRect.width:
                break
 
            # Keep the item rectangle, will be used later in functions such
            # as 'OnLeftDown', 'OnMouseMove'
            copy = wx.Rect(*rect)
            copy.Inflate(0, SPACER)
            item.SetRect(copy)
 
            if item.GetState() == ControlFocus:
                ArtManager.Get().SetMS2007ButtonSunken(True)
                ArtManager.Get().DrawButton(dc, item.GetRect(), ArtManager.Get().GetMenuTheme(), ControlFocus, False)
 
            ww, hh = dc.GetTextExtent(labelOnly)
            textOffset = (rect.width - ww) / 2
 
            if item.GetTextBitmap().Ok():
 
                dc.DrawBitmap(item.GetTextBitmap(), rect.x, rect.y, True)
 
            else:
 
                # Draw the text on a bitmap using memory dc, 
                # so on following calls we will use this bitmap instead
                # of calculating everything from scratch
                bmp = wx.EmptyBitmap(rect.width, rect.height)
                memDc = wx.MemoryDC()
                memDc.SelectObject(bmp)
 
                # Fill the bitmap with the maksing colour
                memDc.SetPen(wx.Pen(wx.Colour(0, 128, 128)) )
                memDc.SetBrush(wx.Brush(wx.Colour(0, 128, 128)) )
                memDc.DrawRectangle(0, 0, rect.width, rect.height)
                memDc.SetFont(fnt)
 
                if location == wx.NOT_FOUND or location >= len(fixedText):
 
                    # draw the text
                    memDc.DrawText(title, textOffset, 0)
                    dc.DrawText(title, rect.x + textOffset, rect.y)
 
                else:
 
                    # underline the first '&'
                    before = labelOnly[0:location]
                    underlineLetter = labelOnly[location] 
                    after = labelOnly[location+1:]
 
                    # before
                    memDc.DrawText(before, textOffset, 0)
                    dc.DrawText(before, rect.x + textOffset, rect.y)
 
                    # underlineLetter
                    if "__WXGTK__" not in wx.Platform:
                        w1, h = dc.GetTextExtent(before)
                        fnt.SetUnderlined(True)
                        dc.SetFont(fnt)
                        memDc.SetFont(fnt)
 
                        memDc.DrawText(underlineLetter, textOffset + w1, 0)
                        dc.DrawText(underlineLetter, rect.x + w1 + textOffset, rect.y)
                    else:
                        w1, h = dc.GetTextExtent(before)
                        memDc.DrawText(underlineLetter, textOffset + w1, 0)
                        dc.DrawText(underlineLetter, rect.x + w1 + textOffset, rect.y)
 
                        # 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)
                        dc.DrawLine(rect.x + w1 + textOffset, rect.y + uderlineLetterH - 2,
                                    rect.x + w1 + textOffset + uderlineLetterW, rect.y + uderlineLetterH - 2)
 
                    # after
                    w2, h = dc.GetTextExtent(underlineLetter)
                    fnt.SetUnderlined(False)
                    dc.SetFont(fnt)
                    memDc.SetFont(fnt)
 
                    memDc.DrawText(after,  w1 + w2 + textOffset, 0)
                    dc.DrawText(after, rect.x + w1 + w2 + textOffset, rect.y)
 
                memDc.SelectObject(wx.NullBitmap)
 
                # Set masking colour to the bitmap
                bmp.SetMask(wx.Mask(bmp, wx.Colour(0, 128, 128)))
                item.SetTextBitmap(bmp)
 
            posx += rect.width
 
        if self._showToolbar:
 
            if len(self._tbButtons) == 0:
                return
 
            if len(self._items) == 0:
                rectHeight = clientRect.height - posy - 2*SPACER
                rectWidth  = clientRect.width - moreMenubtnBgBmpRect.width - 3*SPACER
                rectX      = SPACER
                rectY      = posy
            else:
                rectHeight = clientRect.height - 2*SPACER - self._items[0].GetRect().height
                rectWidth  = clientRect.width - moreMenubtnBgBmpRect.width - 3*SPACER
                rectX      = SPACER
                rectY      = self._items[0].GetRect().y + self._items[0].GetRect().height
 
            rr = wx.Rect(rectX, rectY, rectWidth, rectHeight)
            ArtManager.Get().DrawToolBarBg(dc, rr)
            self.DrawToolbar(dc, rr)
 
 
    def DrawToolbar(self, dc, rect):
        """ Draws the toolbar with the given dc & rect. """
 
        width = self._tbIconSize + SPACER
        height = self._tbIconSize + SPACER
        xx = rect.x
        yy = rect.y + (rect.height - height)/2
 
        # by default set all toolbar items as invisible
        for but in self._tbButtons:
            but._visible = False
 
        # Get all the toolbar items
        for i in xrange(len(self._tbButtons)):
 
            # the button width depends on its type
            if self._tbButtons[i]._tbItem.IsSeparator():
                width = SEPARATOR_WIDTH
            else:
                width = self._tbIconSize + SPACER   # normal bitmap's width
 
            # can we keep drawing?
            if xx + width >= rect.width:
                break
 
            # mark this item as visible
            self._tbButtons[i]._visible = True
 
            bmp = wx.NullBitmap
 
            #------------------------------------------
            # special handling for separator
            #------------------------------------------
            if self._tbButtons[i]._tbItem.IsSeparator():
 
                # Place a separator bitmap
                bmp = wx.EmptyBitmap(12, rect.height - 2)
                mem_dc = wx.MemoryDC()
                mem_dc.SelectObject(bmp)
                mem_dc.SetPen(wx.BLACK_PEN)
                mem_dc.SetBrush(wx.BLACK_BRUSH)
 
                mem_dc.DrawRectangle(0, 0, bmp.GetWidth(), bmp.GetHeight())
 
                col = ArtManager.Get().GetMenuBarFaceColour()
                col1 = ArtManager.Get().LightColour(col, 40)
                col2 = ArtManager.Get().LightColour(col, 70)
 
                mem_dc.SetPen(wx.Pen(col2))
                mem_dc.DrawLine(5, 0, 5, bmp.GetHeight())
 
                mem_dc.SetPen(wx.Pen(col1))
                mem_dc.DrawLine(6, 0, 6, bmp.GetHeight())
 
                mem_dc.SelectObject(wx.NullBitmap)
                bmp.SetMask(wx.Mask(bmp, wx.BLACK))
 
                # draw the separator
                buttonRect = wx.Rect(xx, rect.y + 1, bmp.GetWidth(), bmp.GetHeight())
                dc.DrawBitmap(bmp, xx, rect.y + 1, True)
                xx += buttonRect.width
                self._tbButtons[i]._rect = buttonRect
 
                continue
 
            else:
 
                if self._tbButtons[i]._tbItem.IsEnabled():
                    bmp = self._tbButtons[i]._tbItem.GetBitmap()
                else:
                    bmp = self._tbButtons[i]._tbItem.GetDisabledBitmap()
 
            # Draw the toolbar image
            if bmp.Ok():
 
                x = xx
                y = yy + (height - bmp.GetHeight())/2 - 1
 
                buttonRect = wx.Rect(x, y, width, height)
 
                if i < len(self._tbButtons):
 
                    if self._tbButtons[i]._state == ControlFocus:
                        ArtManager.Get().DrawButton(dc, buttonRect, ArtManager.Get().GetMenuTheme(), ControlFocus, False)
                    else:
                        self._tbButtons[i]._state = ControlNormal
 
                imgx = buttonRect.x + (buttonRect.width - bmp.GetWidth())/2
                imgy = buttonRect.y + (buttonRect.height - bmp.GetHeight())/2
 
                if self._tbButtons[i]._state == ControlFocus:
 
                    # in case we the button is in focus, place it 
                    # once pixle up and left
                    # place a dark image under the original image to provide it
                    # with some shadow
                    # shadow = ConvertToMonochrome(bmp)
                    # dc.DrawBitmap(shadow, imgx, imgy, True)
 
                    imgx -= 1
                    imgy -= 1
 
                dc.DrawBitmap(bmp, imgx, imgy, True)
                xx += buttonRect.width
 
                self._tbButtons[i]._rect = buttonRect
                #Edited by P.Kort  
 
                if self._showTooltip == -1:
                    self.SetToolTip(wx.ToolTip("")) 
                else:
                    try:
                        tbitem = self._tbButtons[self._showTooltip]._tbItem
                        msg = tbitem.GetLabel()
                        self.SetToolTip(wx.ToolTip(msg))
                    except:
                        if _debug:
                            print "FlatMenu.py; fn : DrawToolbar; Can't create Tooltip "
                        pass
 
 
    def GetMoreMenuButtonRect(self):
        """ Returns a rectangle surrounding the menu button. """
 
        clientRect = self.GetClientRect()
        rect = wx.Rect(*clientRect)
        rect.SetWidth(DROP_DOWN_ARROW_WIDTH)
        rect.SetX(clientRect.GetWidth() + rect.GetX() - DROP_DOWN_ARROW_WIDTH - 3)
        rect.SetY(2)
        rect.SetHeight(rect.GetHeight() - SPACER)
 
        return rect
 
 
    def DrawMoreButton(self, dc, fr, state):
        """ Draws 'more' button to the right side of the menu bar. """
 
        # Draw a drop down menu at the right position of the menu bar
        # we use xpm file with 16x16 size, another 4 pixels we take as spacer
        # from the right side of the frame, this will create a DROP_DOWN_ARROW_WIDTH  pixels width
        # of unwanted zone on the right side
 
        rect = self.GetMoreMenuButtonRect()
 
        # Draw the bitmap
        if state != ControlNormal:
            # Draw background according to state
            ArtManager.Get().SetMS2007ButtonSunken(True)
            ArtManager.Get().DrawButton(dc, rect, ArtManager.Get().GetMenuTheme(), state, False)
        else:
            # Delete current image
            if self._moreMenuBgBmp.Ok():
                dc.DrawBitmap(self._moreMenuBgBmp, rect.x, rect.y, True)
 
 
        dropArrowBmp = ArtManager.Get().GetStockBitmap("arrow_down")
 
        # Calc the image coordinates
        xx = rect.x + (DROP_DOWN_ARROW_WIDTH - dropArrowBmp.GetWidth())/2
        yy = rect.y + (rect.height - dropArrowBmp.GetHeight())/2
 
        dc.DrawBitmap(dropArrowBmp, xx, yy + SPACER, True)        
        self._dropDownButtonState = state
 
 
    def HitTest(self, pt):
        """ HitTest method for FlatMenuBar. """
 
        if self._dropDownButtonArea.Contains(pt):
            return -1, DropDownArrowButton
 
        for ii, item in enumerate(self._items):
            if item.GetRect().Contains(pt):
                return ii, MenuItem
 
        # check for tool bar items
        if self._showToolbar:
            for ii, but in enumerate(self._tbButtons):
                if but._rect.Contains(pt):
                    # locate the corresponded menu item
                    enabled  = but._tbItem.IsEnabled()
                    separator = but._tbItem.IsSeparator()
                    visible  = but._visible
                    if enabled and not separator and visible:
                        self._showTooltip = ii
                        return ii, ToolbarItem
 
        return -1, NoWhere
 
 
    def FindMenuItem(self, id):
        """ Returns a FlatMenuItem according to its id. """
 
        for item in self._items:
            mi = item.GetMenu().FindItem(id)
            if mi:
                return mi
 
        return None
 
 
    def OnSize(self, event):
        """ Handles the wx.EVT_SIZE event for FlatMenuBar. """
 
        self.ClearBitmaps(0)
        self.Refresh()
 
 
    def OnEraseBg(self, event):
        """ Handles the wx.EVT_ERASE_BACKGROUND event for FlatMenuBar. """
 
        pass        
 
 
    def ProcessMouseMoveFromMenu(self, pt):
        """
        This function is called from child menus, this allow a child menu to
        pass the mouse movement event to the menu bar.
        """
 
        idx, where = self.HitTest(pt)
        if where == MenuItem:
            self.ActivateMenu(self._items[idx])
 
 
    def DoMouseMove(self, pt, leftIsDown):
        """ Handles mouse move event. """
 
        # Reset items state
        for item in self._items:
            item.SetState(ControlNormal)
 
        idx, where = self.HitTest(pt)
 
        if where == DropDownArrowButton:
            if self._dropDownButtonState != ControlFocus and not leftIsDown:
                dc = wx.ClientDC(self)
                self.DrawMoreButton(dc, -1, ControlFocus)
 
        elif where == MenuItem:
            self._dropDownButtonState = ControlNormal
            # On Item
            self._items[idx].SetState(ControlFocus)
 
            # If this item is already selected, dont draw it again
            if self._curretHiliteItem == idx:
                return
 
            self._curretHiliteItem = idx
            if self._showToolbar:
 
                # mark all toolbar items as non-hilited
                for but in self._tbButtons:
                    but._state = ControlNormal
 
            self.Refresh()
 
        elif where == ToolbarItem:
 
            if self._showToolbar:
                if idx < len(self._tbButtons) and idx >= 0:
 
                    if self._tbButtons[idx]._state == ControlFocus:
                        return
 
                    # we need to refresh the toolbar
                    active = self.GetActiveToolbarItem()
                    if active != wx.NOT_FOUND:
                        self._tbButtons[active]._state = ControlNormal
 
                    for but in self._tbButtons:
                        but._state = ControlNormal
 
                    self._tbButtons[idx]._state = ControlFocus
                    self.Refresh()
 
        elif where == NoWhere:
 
            refresh = False
 
            if self._dropDownButtonState != ControlNormal:
                refresh = True
                self._dropDownButtonState = ControlNormal
 
            if self._showToolbar:
                tbActiveItem = self.GetActiveToolbarItem()
                if tbActiveItem != wx.NOT_FOUND:
                    self._tbButtons[tbActiveItem]._state = ControlNormal
                    refresh = True
 
            if self._curretHiliteItem != -1:
 
                self._items[self._curretHiliteItem].SetState(ControlNormal)
                self._curretHiliteItem = -1
                self.Refresh()
 
            if refresh:
                self.Refresh()
 
 
 
    def OnMouseMove(self, event):
        """ Handles mouse move event. """
 
        pt = event.GetPosition()
        self.DoMouseMove(pt, event.LeftIsDown())
 
 
    def ResetToolbarItems(self):
        """ Used internally. """
 
        for but in self._tbButtons:
            but._state = ControlNormal
 
 
    def GetActiveToolbarItem(self):
        """ Returns the active toolbar item. """
 
        for but in self._tbButtons:
 
            if but._state == ControlFocus or but._state == ControlPressed:
                return self._tbButtons.index(but)
 
        return wx.NOT_FOUND
 
 
    def OnLeaveWindow(self, event):
        """ Handles the wx.EVT_LEAVE_WINDOW event for FlatMenuBar (GTK Only). """
 
        self._curretHiliteItem = -1
        self._dropDownButtonState = ControlNormal
 
        # Reset items state
        for item in self._items:
            item.SetState(ControlNormal)
 
        for but in self._tbButtons:
            but._state = ControlNormal
 
        self.Refresh()
 
 
    def OnMenuDismissed(self, event):
        """ Handles menu dismiss event. """
 
        pt = wx.GetMousePosition()
        pt = self.ScreenToClient(pt)
 
        idx, where = self.HitTest(pt)
 
        if where not in [MenuItem, DropDownArrowButton]:
            self._dropDownButtonState = ControlNormal
            self._curretHiliteItem = -1
            for item in self._items:
                item.SetState(ControlNormal)
 
            self.Refresh()
 
 
    def OnLeftDown(self, event):
        """ Handles the wx.EVT_LEFT_DOWN event for FlatMenuBar. """
 
        pt = event.GetPosition()
        idx, where = self.HitTest(pt)
 
        if where == DropDownArrowButton:
            dc = wx.ClientDC(self)
            self.DrawMoreButton(dc, -1, ControlPressed)
            self.PopupMoreMenu()
 
        elif where == MenuItem:
            # Position the menu, the GetPosition() return the coords
            # of the button relative to its parent, we need to translate
            # them into the screen coords
            self.ActivateMenu(self._items[idx])
 
        elif where == ToolbarItem:
            # Over a toolbar item
            dc = wx.ClientDC(self)
            self.DrawToolbarItem(dc, idx, ControlPressed)
 
            # TODO:: Do the action specified in this button
            self.DoToolbarAction(idx)
 
 
    def OnLeftUp(self, event):
        """ Handles the wx.EVT_LEFT_UP event for FlatMenuBar. """
 
        pt = event.GetPosition()
        idx, where = self.HitTest(pt)
 
        if where == ToolbarItem:
 
            # Over a toolbar item
            dc = wx.ClientDC(self)
            self.DrawToolbarItem(dc, idx, ControlFocus)
 
 
    def DrawToolbarItem(self, dc, idx, state):
        """ Draws a toolbar item button. """
 
        if idx >= len(self._tbButtons) or idx < 0:
            return
 
        rect = self._tbButtons[idx]._rect
        ArtManager.Get().DrawButton(dc, rect, ArtManager.Get().GetMenuTheme(), state, False)
 
        # draw the bitmap over the highlight 
        buttonRect = wx.Rect(*rect)
        x = rect.x + (buttonRect.width - self._tbButtons[idx]._tbItem.GetBitmap().GetWidth())/2
        y = rect.y + (buttonRect.height - self._tbButtons[idx]._tbItem.GetBitmap().GetHeight())/2
 
        if state == ControlFocus:
 
            # place a dark image under the original image to provide it
            # with some shadow
            # shadow = ConvertToMonochrome(self._tbButtons[idx]._tbItem.GetBitmap())
            # dc.DrawBitmap(shadow, x, y, True)
 
            # in case we the button is in focus, place it 
            # once pixle up and left
            x -= 1
            y -= 1
 
        dc.DrawBitmap(self._tbButtons[idx]._tbItem.GetBitmap(), x, y, True)
 
 
    def ActivateMenu(self, menuInfo):
        """ Activates menu which its info is menuInfo. """
 
        # first make sure all other menus are not popedup
        if menuInfo.GetMenu().IsShown():
            return
 
        idx = wx.NOT_FOUND
 
        for item in self._items:
            item.GetMenu().Dismiss(False, True)
            if item.GetMenu() == menuInfo.GetMenu():
                idx = self._items.index(item)
 
        # Remove the popup menu as well
        if self._moreMenu and self._moreMenu.IsShown():
            self._moreMenu.Dismiss(False, True)
 
        # make sure that the menu item button is highlited
        if idx != wx.NOT_FOUND:
            self._dropDownButtonState = ControlNormal
            self._curretHiliteItem = idx
            for item in self._items:
                item.SetState(ControlNormal)
 
            self._items[idx].SetState(ControlFocus)
            self.Refresh()
 
        rect = menuInfo.GetRect()
        menuPt = self.ClientToScreen(wx.Point(rect.x, rect.y))
        menuInfo.GetMenu().SetOwnerHeight(rect.height)
        menuInfo.GetMenu().Popup(wx.Point(menuPt.x, menuPt.y), self)
 
 
    def DoToolbarAction(self, idx):
        """ Performs a toolbar button pressed. """
 
        # we handle only button clicks
        if not self._tbButtons[idx]._tbItem.IsRegularItem():
            return
 
        # Create the event
        event = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, self._tbButtons[idx]._tbItem.GetId())
        event.SetEventObject(self)
 
        # all events are handled by this control and its parents
        self.GetEventHandler().ProcessEvent(event)
 
 
    def FindMenu(self, title):
        """
        Returns the index of the menu with the given title or wx.NOT_FOUND if
        no such menu exists in this menubar. The title parameter may specify
        either the menu title (with accelerator characters, i.e. "&File") or
        just the menu label ("File") indifferently.
        """
 
        for ii, item in enumerate(self._items):
            accelIdx, labelOnly = ArtManager.Get().GetAccelIndex(item.GetTitle())
 
            if labelOnly == title or item.GetTitle() == title:
                return ii
 
        return wx.NOT_FOUND
 
 
    def GetMenu(self, menuIdx):
        """ Returns the menu at menuIndex (zero-based), user must not release this menu!. """
 
        if menuIdx >= len(self._items) or menuIdx < 0:
            return None
 
        return self._items[menuIdx].GetMenu()
 
 
    def Insert(self, pos, menu, title):
        """
        Inserts the menu at the given position into the menu bar. Inserting menu
        at position 0 will insert it in the very beginning of it, inserting at
        position GetMenuCount() is the same as calling Append().
        """
 
        menu.SetMenuBar(self)
        self._items.insert(pos, MenuEntryInfo(title, menu))
        self.UpdateAcceleratorTable()
        return True
 
 
    def Remove(self, pos):
        """
        Removes the menu from the menu bar and returns the menu object - the
        caller is responsible for deleting it.
        This function may be used together with FlatMenuBar.Insert to change
        the menubar dynamically.
        """
 
        if pos >= len(self._items):
            return None
 
        menu = self._items[pos].GetMenu()
        self._items.pop(pos)
        self.UpdateAcceleratorTable()
 
        # Since we use bitmaps to optimize our drawings, we need
        # to reset all bitmaps from pos and until end of vector
        # to force size/position changes to the menu bar
        self.ClearBitmaps(pos)
        self.Refresh()
 
        # remove the connection to this menubar
        menu.SetMenuBar(None)
        return menu
 
 
    def UpdateAcceleratorTable(self):
        """ Updates the parent accelerator table. """
 
        # first get the number of items we have
        updatedTable = []
        menubarTable = []
 
        for item in self._items:
 
            updatedTable = item.GetMenu().GetAccelArray() + updatedTable 
 
            # create accelerator for every menu (if it exist)
            title = item.GetTitle()
            mnemonic, labelOnly = ArtManager.Get().GetAccelIndex(title)
 
            if mnemonic != wx.NOT_FOUND:
 
                # Get the accelrator character
                accelChar = labelOnly[mnemonic] 
                accelString = "\tAlt+" + accelChar
                title += accelString
 
                accel = wx.GetAccelFromString(title)
 
                if accel:
 
                    # connect an event to this cmd
                    self.GetParent().Connect(item.GetCmdId(), -1, wx.wxEVT_COMMAND_MENU_SELECTED, self.OnAccelCmd)
                    accel.Set(accel.GetFlags(), accel.GetKeyCode(), item.GetCmdId())
                    updatedTable.append(accel)
                    del accel
 
        entries = [wx.AcceleratorEntry() for ii in xrange(len(updatedTable))]
 
        # Add the new menu items
        for i in xrange(len(updatedTable)):
            entries[i] = updatedTable[i]
 
        table = wx.AcceleratorTable(entries)
        del entries
 
        self.GetParent().SetAcceleratorTable(table)
 
 
    def ClearBitmaps(self, start):
        """
        Erase cached bitmaps. To increase performance of the drawings, the text
        drawing is done into a bitmaps and used later for next drawings.
        """
 
        for item in self._items:
            item.SetTextBitmap(wx.NullBitmap)
 
 
    def OnAccelCmd(self, event):
        """ Single function to handle any accelerator key used inside the menubar. """
 
        for item in self._items:
            if item.GetCmdId() == event.GetId():
                self.ActivateMenu(item)
 
 
    def ActivateNextMenu(self):
        """ Activates next menu and make sure all other are non-active. """
 
        last_item = self.GetLastVisibleMenu()
        # find the current active menu
        for i in xrange(last_item+1):
            if self._items[i].GetMenu().IsShown():
                nextMenu = i + 1
                if nextMenu >= last_item:
                    nextMenu = 0
                self.ActivateMenu(self._items[nextMenu])
                return
 
 
    def GetLastVisibleMenu(self):
        """ Returns the index of the last visible menu on the menu bar. """
 
        last_item = 0
 
        # find the last visible item
        rect = wx.Rect()
 
        for item in self._items:
 
            if item.GetRect() == rect:
                break
 
            last_item += 1
 
        return last_item
 
 
    def ActivatePreviousMenu(self):
        """ Activates previous menu and make sure all other are non-active. """
 
        # find the current active menu
        last_item = self.GetLastVisibleMenu()
 
        for i in xrange(last_item):
            if self._items[i].GetMenu().IsShown():
                prevMenu = i - 1
                if prevMenu < 0:
                    prevMenu = last_item - 1
 
                if prevMenu < 0:
                    return
 
                self.ActivateMenu(self._items[prevMenu])
                return
 
 
    def CreateMoreMenu(self):
        """ Creates the drop down menu and populate it. """
 
        if not self._moreMenu: 
            # first time
            self._moreMenu = FlatMenu()
            self._popupDlgCmdId = wx.NewId()
 
            # Connect an event handler for this event
            self.Connect(self._popupDlgCmdId, -1, wx.wxEVT_COMMAND_MENU_SELECTED, self.OnCustimizeDlg)
 
        # Remove all items from the popup menu
        self._moreMenu.Clear()
 
        lastVisibleItem = self.GetLastVisibleMenu()
 
        for i in xrange(lastVisibleItem, len(self._items)):
            item = FlatMenuItem(self._moreMenu, wx.ID_ANY, self._items[i].GetTitle(),
                                "", wx.ITEM_NORMAL, self._items[i].GetMenu())
            self._moreMenu.AppendItem(item)
 
        if lastVisibleItem < len(self._items):
            self._moreMenu.AppendSeparator()
 
        # Add invisible toolbar items
        if self._showToolbar:
 
            for ii in xrange(len(self._tbButtons)):
 
                if self._tbButtons[ii]._visible == False:
                    break
 
                count = ii
 
            if count < len(self._tbButtons) - 1:
 
                # We have hidden toolbar items, show them!
                if not self._tbMenu:
                    self._tbMenu = FlatMenu()
 
                self._tbMenu.Clear()
 
                for i in xrange(count+1, len(self._tbButtons)):
 
                    if self._tbButtons[i]._tbItem.IsSeparator():
                        self._tbMenu.AppendSeparator()
                    else:
                        tbitem = self._tbButtons[i]._tbItem
                        item = FlatMenuItem(self._tbMenu, tbitem.GetId(), tbitem.GetLabel(), "", wx.ITEM_NORMAL, None, tbitem.GetBitmap(), tbitem.GetDisabledBitmap())
                        item.Enable(tbitem.IsEnabled())
                        self._tbMenu.AppendItem(item)                    
 
                item = FlatMenuItem(self._moreMenu, wx.ID_ANY, "ToolBar Items", "", wx.ITEM_NORMAL, self._tbMenu)
                self._moreMenu.AppendItem(item)
                self._moreMenu.AppendSeparator()
 
        item = FlatMenuItem(self._moreMenu, self._popupDlgCmdId, "Customize ...")
        self._moreMenu.AppendItem(item)
 
 
    def PopupMoreMenu(self):
        """ Popups the 'more' menu. """
 
        self.CreateMoreMenu()
 
        pt = self._dropDownButtonArea.GetTopLeft()
        pt = self.ClientToScreen(pt)
        pt.y += self._dropDownButtonArea.GetHeight()
        self._moreMenu.Popup(pt, self)
 
 
    def OnCustimizeDlg(self, event):
        """ Handles the customize dialog here. """
 
        if not self._dlg:
            self._dlg = FMCustomizeDlg(self)
        else:
            # intialize the dialog
            self._dlg.Initialise()
 
        if self._dlg.ShowModal() == wx.ID_OK:
            # Handle customize requests here
            pass
 
        if "__WXGTK__" in wx.Platform:
            # Reset the more button
            dc = wx.ClientDC(self)
            self.DrawMoreButton(dc, -1, ControlNormal)
 
 
    def AppendToolbarItem(self, item):
        """ Appends toolbar item to this menu bar. """
 
        newItem = ToolBarItem(item, wx.Rect(), ControlNormal)
        self._tbButtons.append(newItem)
 
 
    def SetUpdateInterval(self, interval):
        """
        Sets the updateUI interval for toolbar items. All UpdateUI events are
        sent from within OnIdle() handler, the default is 20 milliseconds.
        """
 
        self._interval = interval
 
 
    def PositionAUI(self, mgr):
        """ Positions the control inside wxAUI frame manager. """
 
        pn = AUI.PaneInfo()
        xx = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X)
 
        # We add our menu bar as a toolbar, with the following settings
        pn.BestSize(wx.Size(xx, self.GetSize().y))
        pn.FloatingSize(wx.Size(300, self.GetSize().y))
        pn.Floatable(False)
        pn.Dockable(False)
        pn.CaptionVisible(False)
        pn.PaneBorder(False)
        pn.MinSize(wx.Size(xx, self.GetSize().y))
        pn.MaxSize(wx.Size(xx, self.GetSize().y))
        pn.Top()
        pn.Name("flat_menu_bar")
        pn.Caption("Menu Bar")
        mgr.AddPane(self, pn)
 
 
# ---------------------------------------------------------------------------- #
# Class ShadowPopupWindow
# ---------------------------------------------------------------------------- #
 
class ShadowPopupWindow(wx.PopupWindow):
    """ Base class for generic FlatMenu derived from wx.PopupWindow. """
 
    def __init__(self):
        """ Default class constructor. """
 
        parent = wx.GetApp().GetTopWindow()
        if not parent:
            raise "Can't create menu without parent!"
 
        wx.PopupWindow.__init__(self, parent)
 
        if "__WXMSW__" in wx.Platform and _libimported == "MH":
 
            GCL_STYLE= -26
            cstyle= win32gui.GetClassLong(self.GetHandle(), GCL_STYLE)
            if cstyle & CS_DROPSHADOW == 0:
                win32api.SetClassLong(self.GetHandle(),
                                      GCL_STYLE, cstyle | CS_DROPSHADOW)
 
        # popup windows are created hidden by default
        self.Hide()
 
 
    def CreateMSW(self):
        """ Create MSW-style PopupWindow with shadows. Not used at present. """
 
        className = "wxMenuNR"
 
        # Register class 
        wndclass = win32gui.WNDCLASS()
 
        # for each class we register one with CS_(V|H)REDRAW style and one
        # without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
        styleNoRedraw = win32con.CS_DBLCLKS
        version = wx.GetOsDescription()
        if version.find("XP") >= 0 or version.find("2000") >= 0:
            # This style is available from WIN2K and above
            styleNoRedraw |= CS_DROPSHADOW
 
        # the fields which are common to all classes
        wndclass.lpfnWndProc   = self.WndProc
        wndclass.hInstance     = winxpgui.GetModuleHandle(None)
 
        wndclass.hCursor       = 65553
 
        # register the class for all normal windows
        wndclass.hbrBackground = winxpgui.GetStockObject(win32con.COLOR_BTNFACE+1)
        wndclass.lpszClassName = className
        wndclass.style         = styleNoRedraw
 
        try:
            win32gui.RegisterClass(wndclass)
        except:
            # most probably class is already registered
            pass
 
        # choose the position/size for the new window
        x, y, w, h = MSWGetCreateWindowCoords(self.pre.GetPosition(), self.pre.GetSize())
 
        # controlId is menu handle for the top level windows, so set it to 0
        # unless we're creating a child window
        controlId = (self.pre.GetWindowStyleFlag() & win32con.WS_CHILD and [self.pre.GetId()] or [0])[0]
 
        msflags = self.MSWGetStyle(self.pre.GetWindowStyle()) 
 
        # do create the window
        win32gui.DestroyWindow(self.pre.GetHandle())
 
        self._hWnd = winxpgui.CreateWindowEx(0,
                                             className,
                                             "ShadowWindow",
                                             msflags,
                                             x, y, w, h,
                                             self.pre.GetParent().GetHandle(),
                                             controlId,
                                             winxpgui.GetModuleHandle(None),
                                             None)
 
        if not self._hWnd:        
            raise "Can't create window of class wxMenu"
            return
 
 
 
 
    def WndProc(self, hWnd, msg, wparam, lparam):
        """ Used internally. """
 
        # Need not contain anything since the PyCWnd handler
        # processes all messages
        pass
 
 
    def MSWGetStyle(self, flags):
        """ Used internally. """
 
        # translate common wxWidgets styles to Windows ones
        # most of windows are child ones, those which are not (such as
        # wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
        style = win32con.WS_CHILD
 
        # using this flag results in very significant reduction in flicker,
        # especially with controls inside the static boxes (as the interior of the
        # box is not redrawn twice), but sometimes results in redraw problems, so
        # optionally allow the old code to continue to use it provided a special
        # system option is turned on
        if not wx.SystemOptions_GetOptionInt("msw.window.no-clip-children") or flags & wx.CLIP_CHILDREN:
            style |= win32con.WS_CLIPCHILDREN
 
        # it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
        # don't support overlapping windows and it only makes sense for them and,
        # presumably, gives the system some extra work (to manage more clipping
        # regions), so avoid it alltogether
 
        if flags & wx.VSCROLL:
            style |= win32con.WS_VSCROLL
 
        if flags & wx.HSCROLL:
            style |= win32con.WS_HSCROLL
 
        border = self.pre.GetBorder(flags)
 
        # WS_BORDER is only required for wxBORDER_SIMPLE
        if border == wx.BORDER_SIMPLE:
            style |= win32con.WS_BORDER
 
        return style
 
 
#--------------------------------------------------------
# Class FlatMenuButton
#--------------------------------------------------------
 
class FlatMenuButton:
    """
    A nice small class that functions like wx.BitmapButton, the reason I did
    not used BitmapButton is that on Linux, it has some extra margins that
    I can't seem to be able to remove.
    """
 
    def __init__(self, menu, up, normalBmp, disabledBmp=wx.NullBitmap):
        """
        Default class constructor.
 
        Parameters:
        @up: True for up arrow or False for down arrow;
        @normalBmp: normal state bitmap;
        @disabledBmp: disabled state bitmap.
        """
 
        self._normalBmp = normalBmp
        self._up = up
        self._parent = menu
        self._pos = wx.Point()
        self._size = wx.Size()
        self._timerID = wx.NewId()
 
        if not disabledBmp.Ok():
            self._disabledBmp = ArtManager.Get().CreateGreyBitmap(self._normalBmp)
        else: 
            self._disabledBmp = disabledBmp
 
        self._state = ControlNormal
        self._timer = wx.Timer(self._parent, self._timerID)
        self._timer.Stop()
 
 
    def __del__(self):
        """ Used internally. """
 
        if self._timer:
            if self._timer.IsRunning():
                self._timer.Stop()
 
            del self._timer
 
 
    def Contains(self, pt):
        """ Used internally. """
 
        rect = wx.RectPS(self._pos, self._size)
        if not rect.Contains(pt):
            return False
 
        return True
 
 
    def Draw(self, dc):
        """ Draws self at rect using dc. """
 
        rect = wx.RectPS(self._pos, self._size)
        xx = rect.x + (rect.width - self._normalBmp.GetWidth())/2
        yy = rect.y + (rect.height - self._normalBmp.GetHeight())/2
 
        ArtManager.Get().DrawButton(dc, rect, Style2007, self._state, wx.BLACK)
        dc.DrawBitmap(self._normalBmp, xx, yy, True)
 
 
    def ProcessLeftDown(self, pt):
        """ Handles left down mouse events. """
 
        if not self.Contains(pt):
            return False
 
        self._state = ControlPressed
        self._parent.Refresh()
 
        if self._up:
            self._parent.ScrollUp()
        else:
            self._parent.ScrollDown()
 
        self._timer.Start(100)
        return True
 
 
    def ProcessLeftUp(self, pt):
        """ Handles left up mouse events. """
 
        # always stop the timer
        self._timer.Stop()
 
        if not self.Contains(pt):
            return False
 
        self._state = ControlFocus
        self._parent.Refresh()
 
        return True
 
 
    def ProcessMouseMove(self, pt):
        """ Handles mouse move events. """
 
        # pt is in parent coordiantes, convert it to our
        if not self.Contains(pt):
 
            self._timer.Stop()
            if self._state != ControlNormal:
 
                self._state = ControlNormal
                self._parent.Refresh()
 
            return False
 
        # Process mouse move event
        if self._state != ControlFocus:
            if self._state != ControlPressed:
                self._state = ControlFocus
                self._parent.Refresh()
 
        return True
 
 
    def GetTimerId(self):
        """ Returns the timer object ID. """
 
        return self._timerID
 
 
    def GetTimer(self):
        """ Returns the timer object. """
 
        return self._timer
 
 
    def Move(self, input1, input2=None):
        """ Moves FlatMenuButton to the specified position. """
 
        if type(input) == type(1):
            self._pos = wx.Point(input1, input2)
        else:
            self._pos = input1
 
 
    def SetSize(self, input1, input2=None):
        """ Sets the size for FlatMenuButton. """
 
        if type(input) == type(1):
            self._size = wx.Size(input1, input2)
        else:
            self._size = input1
 
 
    def GetClientRect(self):
        """ Returns the client rect for FlatMenuButton. """
 
        return wx.RectPS(self._pos, self._size)
 
 
#--------------------------------------------------------
# Class FlatMenuItemGroup
#--------------------------------------------------------
 
class FlatMenuItemGroup:
    """
    A class that manages a group of radio menu items.
    """
 
    def __init__(self):
        """ Default class constructor. """
 
        self._items = []
 
 
    def GetSelectedItem(self):
        """ Returns the selected item. """
 
        for item in self._items:
            if item.IsChecked():
                return item
 
        return None
 
 
    def Add(self, item):
        """ Adds a new item to the group. """
 
        if item.IsChecked():
            # uncheck all other items
            for exitem in self._items:
                exitem._bIsChecked = False
 
        self._items.append(item)
 
 
    def Exist(self, item):
        """ Checks if an item is in the group. """
 
        if item in self._items:
            return True
 
        return False
 
 
    def SetSelection(self, item):
        """ Selects a particular item. """
 
        # make sure this item exist in our group
        if not self.Exist(item):
            return
 
        # uncheck all other items
        for exitem in self._items:
            exitem._bIsChecked = False
 
        item._bIsChecked = True
 
 
    def Remove(self, item):
        """ Removes a particular item. """
 
        if item not in self._items:
            return
 
        self._items.remove(item)
 
        if item.IsChecked() and len(self._items) > 0:
            #if the removed item was the selected one,
            # select the first one in the group
            self._items[0]._bIsChecked = True
 
 
#--------------------------------------------------------
# Class FlatMenuBase
#--------------------------------------------------------
 
class FlatMenuBase(ShadowPopupWindow):
    """
    Base class for generic flat menu derived from wx.PopupWindow.
    """
 
    def __init__(self):
        """ Default class constructor. """
 
        self._parentMenu = None
        self._openedSubMenu = None
        self._owner = None
        self._popupPtOffset = 0
        self._showScrollButtons = False
        self._upButton = None
        self._downButton = None
 
        ShadowPopupWindow.__init__(self)
 
 
    def OnDismiss(self):
        """ Fires an event EVT_FLAT_MENU_DISMISSED and handle menu dismiss. """
 
        # Release mouse capture if needed
        if self.HasCapture():
            self.ReleaseMouse()
 
        # send an event about our dismissal to the parent (unless we are a sub menu)
        if self.IsShown() and not self._parentMenu:
 
            event = FlatMenuEvent(wxEVT_FLAT_MENU_DISMISSED, self.GetId())
            event.SetEventObject(self)
 
            # Send it
            if self.GetMenuOwner():
                self.GetMenuOwner().GetEventHandler().ProcessEvent(event)
            else:
                self.GetEventHandler().ProcessEvent(event)
 
 
    def Popup(self, pt, parent):
        """
        Popups menu at point 'pt'. 'pt' assumed to be in screen coordinates. However,
        if parent is not None, 'pt' is translated into the screen coordinates using
        parent.ClientToScreen().
        """
 
        # some controls update themselves from OnIdle() call - let them do it
        wx.GetApp().ProcessIdle()
 
        # The mouse was pressed in the parent coordinates, 
        # e.g. pressing on the left top of a text ctrl
        # will result in (1, 1), these coordinates needs
        # to be converted into screen coords
        self._parentMenu = parent
 
        # If we are topmost menu, we use the given pt
        # else we use the logical 
        # parent (second argument provided to this function)
 
        if self._parentMenu:
            pos = self._parentMenu.ClientToScreen(pt)
        else:
            pos = pt
 
        # Fit the menu into screen
        pos = self.AdjustPosition(pos)
 
        if self._showScrollButtons:
 
            sz = self.GetSize()
            # Get the screen height
            scrHeight = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y)
 
            if not self._upButton:
                self._upButton = FlatMenuButton(self, True, ArtManager.Get().GetStockBitmap("arrow_up"))
 
            if not self._downButton:
                self._downButton = FlatMenuButton(self, False, ArtManager.Get().GetStockBitmap("arrow_down"))
 
            # position the scrollbar
            self._upButton.SetSize((SCROLL_BTN_HEIGHT, SCROLL_BTN_HEIGHT))
            self._downButton.SetSize((SCROLL_BTN_HEIGHT, SCROLL_BTN_HEIGHT))
 
            self._upButton.Move((sz.x - SCROLL_BTN_HEIGHT - 4, 4))
            self._downButton.Move((sz.x - SCROLL_BTN_HEIGHT - 4, scrHeight - pos.y - 2 - SCROLL_BTN_HEIGHT))
 
        self.Move(pos)
        self.Show()
 
        # Capture mouse event and direct them to us
        self.CaptureMouse()
 
 
    def AdjustPosition(self, pos):
        """ Adjusts position so the menu will be fully visible on screen. """
 
        # Check that the menu can fully appear in the screen
        scrWidth  = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X)
        scrHeight = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y)
 
        size = self.GetSize()
 
        # always assume that we have scrollbuttons on
        self._showScrollButtons = False
        pos.y += self._popupPtOffset
 
        if size.y + pos.y > scrHeight:
            # the menu will be truncated
            if self._parentMenu is None:
                # try to flip the menu
                flippedPosy = pos.y - size.y
                flippedPosy -= self._popupPtOffset
 
                if flippedPosy >= 0 and flippedPosy + size.y < scrHeight:
                    pos.y = flippedPosy
                    return pos
                else: 
                    # We need to popup scrollbuttons!
                    self._showScrollButtons = True
 
            else: 
                # we are a submenu
                # try to decrease the y value of the menu position
                newy = pos.y
                newy -= (size.y + pos.y) - scrHeight
 
                if newy + size.y > scrHeight:
                    # probably the menu size is too high to fit
                    # the screen, we need scrollbuttons
                    self._showScrollButtons = True
                else:
                    pos.y = newy
 
        menuMaxX = pos.x + size.x
 
        if menuMaxX > scrWidth:
 
            if self._parentMenu:
 
                # We are submenu
                self._shiftePos = (size.x + self._parentMenu.GetSize().x)
                pos.x -= self._shiftePos
                pos.x += 10
 
            else:
 
                self._shiftePos  = ((size.x + pos.x) - scrWidth)            
                pos.x -= self._shiftePos
 
        else:
 
            if self._parentMenu:
                pos.x += 5
 
        return pos
 
 
    def Dismiss(self, dismissParent, resetOwner):
        """ Dismisses the popup window. """
 
        # Check if child menu is poped, if so, dismiss it
        if self._openedSubMenu:
            self._openedSubMenu.Dismiss(False, resetOwner)
 
        self.OnDismiss()
 
        # Reset menu owner
        if resetOwner:
            self._owner = None
 
        self.Show(False)
 
        if self._parentMenu and dismissParent:
 
            self._parentMenu.OnChildDismiss()
            self._parentMenu.Dismiss(dismissParent, resetOwner)
 
        self._parentMenu = None
 
 
    def OnChildDismiss(self):
        """ Handles children dismiss. """
 
        self._openedSubMenu = None
 
 
    def GetRootMenu(self):
        """ Gets the top level menu. """
 
        root = self
        while root._parentMenu:
            root = root._parentMenu
 
        return root
 
 
    def SetOwnerHeight(self, height):
        """
        Sets the menu owner height, this will be used to position the menu below
        or above the owner.
        """
 
        self._popupPtOffset = height
 
 
    # by default do nothing
    def ScrollDown(self):
        """
        Scroll one unit down.
        By default this function is empty, let derived class do something.
        """
 
        return False
 
 
    # by default do nothing
    def ScrollUp(self):
        """
        Scroll one unit up.
        By default this function is empty, let derived class do something.
        """
 
        return False
 
 
    def GetMenuOwner(self):
        """
        Returns the menu logical owner, the owner does not necessarly mean the
        menu parent, it can also be the window that popped up it.
        """
 
        return self._owner
 
 
#--------------------------------------------------------
# Class ToolBarItem
#--------------------------------------------------------
 
class ToolBarItem:
    """
    A simple class that holds information about a toolbar item.
    """
 
    def __init__(self, tbItem, rect, state):
        """ Default class constructor. """
 
        self._tbItem = tbItem
        self._rect = rect
        self._state = state
        self._visible = True
 
 
#--------------------------------------------------------
# Class FlatToolBarItem
#--------------------------------------------------------
 
class FlatToolbarItem:
    """
    This class represents a toolbar item.
    """
 
    def __init__(self, controlType=None, id=wx.ID_ANY, label="", disabledBmp=wx.NullBitmap, kind=ToolbarItemButton):
        """ Default class constructor. """
 
        if id == wx.ID_ANY:
            id = wx.NewId()
 
        if controlType is None:    # Is a separator
            self._normalBmp = wx.NullBitmap
            self._id = wx.NewId()
            self._label = ""
            self._disabledImg = wx.NullBitmap
            self._customCtrl = None
            kind = ToolbarItemSeparator
 
        elif isinstance(controlType, wx.Bitmap):   # Bitmap construction, simple tool
            self._normalBmp = controlType
            self._id = id
            self._label = label
            self._disabledImg = disabledBmp
            self._customCtrl = None
 
            if not self._disabledImg.Ok():
                # Create a grey bitmap from the normal bitmap
                self._disabledImg = ArtManager.Get().CreateGreyBitmap(self._normalBmp)
 
        elif issubclass(controlType, wx.Window): # is a wxControl
            self._normalBmp = wx.NullBitmap
            self._id = id
            self._label = ""
            self._disabledImg = wx.NullBitmap
            self._customCtrl = controlType
            kind = ToolbarItemCustom
 
        self._kind = kind
        self._enabled = True
 
 
    def GetLabel(self):
        """ Returns the tool label. """
 
        return self._label
 
 
    def SetLabel(self, label):
        """ Sets the tool label. """
 
        self._label = label
 
 
    def GetBitmap(self):
        """ Returns the tool bitmap. """
 
        return self._normalBmp
 
 
    def SetBitmap(self, bmp):
        """ Sets the tool bitmap. """
 
        self._normalBmp = bmp
 
 
    def GetDisabledBitmap(self):
        """ Returns the tool disabled bitmap. """
 
        return self._disabledImg
 
 
    def SetDisabledBitmap(self, bmp):
        """ Sets the tool disabled bitmap. """
 
        self._disabledImg = bmp
 
 
    def GetId(self):
        """ Gets the tool id. """
 
        return self._id
 
 
    def IsSeparator(self):
        """ Returns whether the tool is a separator or not. """
 
        return self._kind == ToolbarItemSeparator
 
 
    def IsCustomControl(self):
        """ Returns whether the tool is a custom control or not. """
 
        return self._kind == ToolbarItemCustom
 
 
    def IsRegularItem(self):
        """ Returns whether the tool is a standard tool or not. """
 
        return self._kind == ToolbarItemButton
 
 
    def GetCustomControl(self):
        """ Returns the associated custom control. """
 
        return self._customCtrl
 
 
    def IsEnabled(self):
        """ Returns whether the tool is enabled or not. """
 
        return self._enabled
 
 
    def Enable(self, enable=True):
        """ Enables or disables the tool. """
 
        self._enabled = enable
 
 
#--------------------------------------------------------
# Class FlatMenuItem
#--------------------------------------------------------
 
class FlatMenuItem:
    """
    A class that represents an item in a menu.
    """
 
    def __init__(self, parent, id=wx.ID_SEPARATOR, text="", helpString="",
                 kind=wx.ITEM_NORMAL, subMenu=None, normalBmp=wx.NullBitmap,
                 disabledBmp=wx.NullBitmap,
                 hotBmp=wx.NullBitmap):
        """
        Default class constructor.
 
        Parameters:
        @param parent: menu that the menu item belongs to;
        @param label: text for the menu item, as shown on the menu. An accelerator
                      key can be specified using the ampersand '&' character. In
                      order to embed an ampersand character in the menu item text,
                      the ampersand must be doubled;
        @param kind: may be wx.ITEM_SEPARATOR, wx.ITEM_NORMAL, wx.ITEM_CHECK or
                     wx.ITEM_RADIO;
        @param helpString: optional help string that will be shown on the status bar;
        @param normalBmp: normal bitmap to draw to the side of the text, this bitmap
                          is used when the menu is enabled;
        @param disabledBmp: 'greyed' bitmap to draw to the side of the text, this
                             bitmap is used when the menu is disabled, if none supplied
                             normal is used;
        @param hotBmp: hot bitmap to draw to the side of the text, this bitmap is
                       used when the menu is hovered, if non supplied, normal is used.
        """
 
        self._text = text
        self._kind = kind
        self._helpString = helpString
 
        if id == wx.ID_ANY:
            id = wx.NewId()
 
        self._id = id
        self._parentMenu = parent
        self._subMenu = subMenu
        self._normalBmp = normalBmp
        self._disabledBmp = disabledBmp
        self._hotBmp = hotBmp
        self._bIsChecked = False
        self._bIsEnabled = True
        self._mnemonicIdx = wx.NOT_FOUND
        self._isAttachedToMenu = False
        self._accelStr = ""
        self._rect = wx.Rect()
        self._groupPtr = None
        self._visible = False
 
        self.SetLabel(self._text)
 
 
    def Enable(self, enable=True):
        """ Enables or Disables a menu item. """        
 
        self._bIsEnabled = enable
        if self._parentMenu:
            self._parentMenu.UpdateItem(self)
 
 
    def GetBitmap(self):
        """
        Returns the normal bitmap associated to the menu item or wx.NullBitmap if
        not supplied.
        """
 
        return self._normalBmp 
 
 
    def GetDisabledBitmap(self):
        """
        Returns the disabled bitmap associated to the menu item or wx.NullBitmap
        if not supplied.
        """
 
        return self._disabledBmp 
 
 
    def GetHotBitmap(self):
        """
        Returns the hot bitmap associated to the menu item or wx.NullBitmap if
        not supplied.
        """
 
        return self._hotBmp 
 
 
    def GetHelp(self):
        """ Returns the item help string. """
 
        return self._helpString 
 
 
    def GetId(self):
        """ Returns the item id. """
 
        return self._id 
 
 
    def GetKind(self):
        """
        Returns the menu item kind, can be one of wx.ITEM_SEPARATOR, wx.ITEM_NORMAL,
        wx.ITEM_CHECK or wx.ITEM_RADIO.
        """
 
        return self._kind 
 
 
    def GetLabel(self):
        """ Returns the menu item label (without the accelerator if is part of the string). """
 
        return self._label 
 
 
    def GetMenu(self):
        """ Returns the parent menu. """
 
        return self._parentMenu 
 
 
    def GetText(self):
        """ Returns the text associated with the menu item including accelerator. """
 
        return self._text 
 
 
    def GetSubMenu(self):
        """ Returns the sub-menu. """
 
        return self._subMenu
 
 
    def IsCheckable(self):
        """ Returns True if this item is of type wx.ITEM_CHECK, False otherwise. """
 
        return self._kind == wx.ITEM_CHECK
 
 
    def IsChecked(self):
        """ Returns whether an item is checked or not. """
 
        return self._bIsChecked 
 
 
    def IsRadioItem(self):
        """ Returns True if this item is of type wx.ITEM_RADIO, False otherwise. """
 
        return self._kind == wx.ITEM_RADIO
 
 
    def IsEnabled(self):
        """ Returns whether an item is enabled or not. """
 
        return self._bIsEnabled 
 
 
    def IsSeparator(self):
        """ Returns True if this item is of type wx.ITEM_SEPARATOR, False otherwise. """
 
        return self._id == wx.ID_SEPARATOR
 
 
    def IsSubMenu(self):
        """ Returns whether an item is a sub-menu or not. """
 
        return self._subMenu != None
 
 
    def SetNormalBitmap(self, bmp):
        """ Sets the menu item normal bitmap. """
 
        self._normalBmp = bmp 
 
 
    def SetDisabledBitmap(self, bmp):
        """ Sets the menu item disabled bitmap. """
 
        self._disabledBmp = bmp 
 
 
    def SetHotBitmap(self, bmp):
        """ Sets the menu item hot bitmap. """
 
        self._hotBmp = bmp 
 
 
    def SetHelp(self, helpString):
        """ Sets the menu item help string. """
 
        self._helpString = helpString 
 
 
    def SetMenu(self, menu):
        """ Sets the menu item parent menu. """
 
        self._parentMenu = menu 
 
 
    def SetSubMenu(self, menu):
        """ Sets the menu item sub-menu. """
 
        self._subMenu = menu 
 
 
    def GetAccelString(self):
        """ Returns the accelerator string. """
 
        return self._accelStr 
 
 
    def SetRect(self, rect):
        """ Sets the menu item rect. """
 
        self._rect = rect 
 
 
    def GetRect(self):
        """ Returns the menu item rect. """
 
        return self._rect 
 
 
    def IsShown(self):
        """ Returns whether an item is shown or not. """
 
        return self._visible
 
 
    def Show(self, show=True):
        """ Actually shows the menu item. """
 
        self._visible = show
 
 
    def DrawSelf(self, dc, yCoord, imageMarginX, markerMarginX, textX, rightMarginX, selected=False):
        """ Draws the menu item on the specified dc. """
 
        borderXSize = self._parentMenu.GetBorderXWidth()
        itemHeight = self._parentMenu.GetItemHeight()
        menuWidth  = self._parentMenu.GetMenuWidth()
        theme = ArtManager.Get().GetMenuTheme()
        disableColor = ArtManager.Get().LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT), 30)
 
        # Define the item actual rectangle area
        itemRect = wx.Rect(0, yCoord, self._parentMenu.GetMenuWidth(), itemHeight)
 
        # Define the drawing area 
        rect = wx.Rect(2, yCoord, self._parentMenu.GetMenuWidth() - 4, itemHeight)
 
        # Draw the background
        backColor = ArtManager.Get().GetMenuFaceColour()
        penColor  = ArtManager.Get().GetMenuFaceColour()
        backBrush = wx.Brush(backColor)
        pen = wx.Pen(penColor)
        dc.SetPen(pen)
        dc.SetBrush(backBrush)
        dc.DrawRectangleRect(rect)
 
        # Draw the left margin gradient
        self._parentMenu.DrawLeftMargin(dc, itemRect)
 
        # check if separator
        if self.IsSeparator():
 
            # Separator is a small grey line separating between 
            # menu item. the separator height is 3 pixels
            sepWidth = menuWidth - textX - 1
            sepRect1 = wx.Rect(textX, yCoord + 1, sepWidth/2, 1)
            sepRect2 = wx.Rect(textX + sepWidth/2, yCoord + 1, sepWidth/2-1, 1)
 
            ArtManager.Get().PaintStraightGradientBox(dc, sepRect1, ArtManager.Get().GetMenuFaceColour(),
                                                      wx.NamedColor("LIGHT GREY"), False)
            ArtManager.Get().PaintStraightGradientBox(dc, sepRect2, wx.NamedColor("LIGHT GREY"),
                                                      ArtManager.Get().GetMenuFaceColour(), False)
            return
 
        # Keep the item rect
        self._rect = itemRect
 
        # Get the bitmap base on the item state (disabled, selected ..)
        bmp = self.GetSuitableBitmap(selected)
 
        # First we draw the selection rectangle
        if selected:
            ArtManager.Get().SetMS2007ButtonSunken(False)
            ArtManager.Get().DrawButton(dc, rect, theme, ControlFocus, False)
 
        if bmp.Ok():
 
            # Calculate the postion to place the image
            imgHeight = bmp.GetHeight()
            imgWidth  = bmp.GetWidth()
 
            xx = rect.x + imageMarginX - 1
            yy = rect.y + 1
            rr = wx.Rect(xx, yy, rect.height-2, rect.height-2)
            dc.DrawBitmap(bmp, rr.x + (rr.width - imgWidth)/2, rr.y + (rr.height - imgHeight)/2, True)
 
 
        if self.GetKind() == wx.ITEM_CHECK:
 
            # Checkable item
            if self.IsChecked():
 
                # Draw check 
                checkMarkBmp = wx.BitmapFromXPMData(check_mark_xpm)
                checkMarkBmp.SetMask(wx.Mask(checkMarkBmp, wx.WHITE))
 
                # Draw surrounding rectangle around the selection box
                xx = rect.x + 1
                yy = rect.y + 1
                rr = wx.Rect(xx, yy, rect.height-2, rect.height-2)
 
                if not selected:
                    ArtManager.Get().SetMS2007ButtonSunken(False)
                    ArtManager.Get().DrawButton(dc, rr, theme, ControlFocus, False)
 
                dc.DrawBitmap(checkMarkBmp, rr.x + (rr.width - 16)/2, rr.y + (rr.height - 16)/2, True)
 
        if self.GetKind() == wx.ITEM_RADIO:
 
            # Checkable item
            if self.IsChecked():
 
                # Draw check 
                checkMarkBmp = wx.BitmapFromXPMData(radio_item_xpm)
                checkMarkBmp.SetMask(wx.Mask(checkMarkBmp, wx.WHITE))
 
                # Draw surrounding rectangle around the selection box
                xx = rect.x + 1
                yy = rect.y + 1
                rr = wx.Rect(xx, yy, rect.height-2, rect.height-2)
 
                if not selected:
                    ArtManager.Get().SetMS2007ButtonSunken(False)
                    ArtManager.Get().DrawButton(dc, rr, theme, ControlFocus, False)
 
                dc.DrawBitmap(checkMarkBmp, rr.x + (rr.width - 16)/2, rr.y + (rr.height - 16)/2, True)
 
        # Draw text - without accelerators
        text = self.GetLabel()
 
        if text:
 
            font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
            enabledTxtColour = (ArtManager.Get().GetMenuTheme() == StyleXP and [wx.BLACK] or [wx.NamedColor("MIDNIGHT BLUE")])[0]
            textColor = (self.IsEnabled() and [enabledTxtColour] or [disableColor])[0]
 
            dc.SetFont(font)
            w, h = dc.GetTextExtent(text)
            dc.SetTextForeground(textColor)
 
            if self._mnemonicIdx != wx.NOT_FOUND:
 
                # We divide the drawing to 3 parts
                text1 = text[0:self._mnemonicIdx]
                text2 = text[self._mnemonicIdx]
                text3 = text[self._mnemonicIdx+1:]
 
                w1, dummy = dc.GetTextExtent(text1)
                w2, dummy = dc.GetTextExtent(text2)
                w3, dummy = dc.GetTextExtent(text3)
 
                posx = textX + borderXSize
                posy = (itemHeight - h)/2 + yCoord
 
                # Draw first part 
                dc.DrawText(text1, posx, posy)
 
                # mnemonic 
                if "__WXGTK__" not in wx.Platform:
                    font.SetUnderlined(True)
                    dc.SetFont(font)
 
                posx += w1
                dc.DrawText(text2, posx, posy)
 
                # last part
                font.SetUnderlined(False)
                dc.SetFont(font)
                posx += w2
                dc.DrawText(text3, posx, posy)
 
            else:
 
                w, h = dc.GetTextExtent(text)
                dc.DrawText(text, textX + borderXSize, (itemHeight - h)/2 + yCoord)
 
 
        # Now draw accelerator
        # Accelerators are aligned to the right
        if self.GetAccelString():
 
            font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
            enabledTxtColour = (ArtManager.Get().GetMenuTheme() == StyleXP and [wx.BLACK] or [wx.NamedColor("MIDNIGHT BLUE")])[0]
            textColor = (self.IsEnabled() and [enabledTxtColour] or [disableColor])[0]
            dc.SetFont(font)
            dc.SetTextForeground(textColor)
            accelWidth, accelHeight = dc.GetTextExtent(self.GetAccelString())
            dc.DrawText(self.GetAccelString(), rightMarginX - accelWidth, (itemHeight - accelHeight)/2 + yCoord)
 
        # Check if this item has sub-menu - if it does, draw 
        # right arrow on the right margin
        if self.GetSubMenu():
 
            # Draw check 
            rightArrowBmp = wx.BitmapFromXPMData(menu_right_arrow_xpm)
            rightArrowBmp.SetMask(wx.Mask(rightArrowBmp, wx.WHITE))
 
            xx = rightMarginX + borderXSize 
            rr = wx.Rect(xx, rect.y + 1, rect.height-2, rect.height-2)
            dc.DrawBitmap(rightArrowBmp, rr.x + 4, rr.y +(rr.height-16)/2, True)
 
 
    def GetHeight(self):
        """ Returns the menu item height. """
 
        if self.IsSeparator():
            return 3
        else:
            return self._parentMenu._itemHeight
 
 
    def GetSuitableBitmap(self, selected):
        """ Gets the bitmap that should be used based on the item state. """
 
        normalBmp = self._normalBmp
        gBmp = (self._disabledBmp.Ok() and [self._disabledBmp] or [self._normalBmp])[0]
        hotBmp = (self._hotBmp.Ok() and [self._hotBmp] or [self._normalBmp])[0]
 
        if not self.IsEnabled():
            return gBmp
        elif selected:
            return hotBmp
        else:
            return normalBmp
 
 
    def SetLabel(self, text):
        """ Sets the label text for this item from the text (excluding the accelerator). """
 
        if text:
 
            indx = text.find("\t")
            if indx >= 0:
                self._accelStr = text[indx+1:]
                label = text[0:indx]
            else:
                self._accelStr = ""
                label = text
 
            self._mnemonicIdx, self._label = ArtManager.Get().GetAccelIndex(label)
 
        else:
 
            self._mnemonicIdx = wx.NOT_FOUND
            self._label = ""
 
        if self._parentMenu:
            self._parentMenu.UpdateItem(self)
 
 
    def SetText(self, text):
        """ Sets the text for this menu item (including accelerators). """
 
        self._text = text
        self.SetLabel(self._text)
 
 
    def GetAcceleratorEntry(self):
        """ Returns the accelerator entry associated to this menu item. """
 
        return wx.GetAccelFromString(self.GetText())
 
 
    def GetMnemonicChar(self):
        """ Returns the shortcut char for this menu item. """
 
        if self._mnemonicIdx == wx.NOT_FOUND:
            return 0
 
        mnemonic = self._label[self._mnemonicIdx]
        return mnemonic.lower()
 
 
    def Check(self, check=True):
        """ Checks or unchecks the menu item. """
 
        if self.IsRadioItem() and not self._isAttachedToMenu:
 
            # radio items can be checked only after they are attached to menu
            return
 
        self._bIsChecked = check
 
        # update group
        if self.IsRadioItem() and check:
            self._groupPtr.SetSelection(self)
 
        # Our parent menu might want to do something with this change
        if self._parentMenu:
            self._parentMenu.UpdateItem(self)
 
 
#--------------------------------------------------------
# Class FlatMenu
#--------------------------------------------------------
 
class FlatMenu(FlatMenuBase):
    """
    A Flat popup menu generic implementation.
    """
 
    def __init__(self):
        """ Default class constructor. """
 
        self._menuWidth = 2*26
        self._leftMarginWidth = 26
        self._rightMarginWidth = 30
        self._borderXWidth = 1
        self._borderYWidth = 2
        self._activeWin = None
        self._focusWin = None
        self._imgMarginX = 0
        self._markerMarginX = 0
        self._textX = 26
        self._rightMarginPosX = -1
        self._itemHeight = 20
        self._selectedItem = -1
        self._clearCurrentSelection = True
        self._textPadding = 8
        self._marginHeight = 20
        self._marginWIdth = 26
        self._accelWidth = 0
        self._mb = None
        self._itemsArr = []
        self._accelArray = []
        self._ptLast = wx.Point()
        self._resizeMenu = True
        self._shiftePos = 0
        self._first = 0
 
        FlatMenuBase.__init__(self)        
 
        self.SetSize(wx.Size(self._menuWidth, self._itemHeight+4))
 
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBg)
        self.Bind(wx.EVT_MOTION, self.OnMouseMove)
        self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeaveWindow)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp)
        self.Bind(wx.EVT_LEFT_DCLICK, self.OnMouseLeftDown)
        self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseRightDown)
        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
        self.Bind(wx.EVT_TIMER, self.OnTimer)
 
 
    def SetMenuBar(self, mb):
        """ Attaches this menu to a menubar. """
 
        self._mb = mb
 
 
    def Popup(self, pt, owner=None, parent=None):
        """ Pops up the menu. """
 
        if "__WXMSW__" in wx.Platform:
            self._mousePtAtStartup = wx.GetMousePosition()
 
        # each time we popup, need to reset the starting index
        self._first = 0
 
        # Loop over self menu and send update UI event for
        # every item in the menu
        numEvents = len(self._itemsArr)
        cc = 0
        self._shiftePos = 0
 
        # Set the owner of the menu. All events will be directed to it.
        # If owner is None, the Default GetParent() is used as the owner
        self._owner = owner
 
        for cc in xrange(numEvents):
            self.SendUIEvent(cc)
 
        # make sure that the menu has the right size before showing it
        self.ResizeMenu()
 
        # Adjust menu position and show it
        FlatMenuBase.Popup(self, pt, parent)
 
        # Replace the event handler of the active window to direct
        # all keyboard events to us and the focused window to direct char events to us
        self._activeWin = wx.GetActiveWindow()
        if self._activeWin:
 
            oldHandler = self._activeWin.GetEventHandler()
            newEvtHandler = MenuKbdRedirector(self, oldHandler)
            self._activeWin.PushEventHandler(newEvtHandler)
 
        if "__WXMSW__" in wx.Platform:
            self._focusWin = wx.Window.FindFocus()
        elif "__WXGTK__" in wx.Platform:
            self._focusWin = self
        else:
            self._focusWin = None
 
        if self._focusWin:
            newEvtHandler = FocusHandler(self)
            self._focusWin.PushEventHandler(newEvtHandler)
 
 
    def Append(self, id, item, helpString, kind):
        """ Appends an item to this menu. """
 
        newItem = FlatMenuItem(self, id, item, helpString, kind)
        return self.AppendItem(newItem)
 
 
    def AppendMenu(self, id, item, subMenu, helpString):
        """ Appends a menu to this menu. """
 
        newItem = FlatMenuItem(self, id, item, helpString, wx.ITEM_NORMAL, subMenu)
        return self.AppendItem(newItem)
 
 
    # The main Append function
    def AppendItem(self, menuItem):
        """ Appends an item to this menu. """
 
        if not menuItem:
            raise "Adding None item?"
            return
 
        # Reparent to us
        menuItem.SetMenu(self) 
        self._itemsArr.append(menuItem)
        menuItem._isAttachedToMenu = True
 
        # Update the menu width if necessary
        menuItemWidth = self.GetMenuItemWidth(menuItem)
        self._menuWidth = (self._menuWidth > menuItemWidth + self._accelWidth and \
                           [self._menuWidth] or [menuItemWidth + self._accelWidth])[0]
 
        menuHeight = 0
 
        for item in self._itemsArr:
            if item.IsSeparator():
                menuHeight += 3
            else:
                menuHeight += self._itemHeight
 
        self.SetSize(wx.Size(self._menuWidth, menuHeight+4))
 
        # Add accelerator entry to the menu if needed
        accel = menuItem.GetAcceleratorEntry()
        if accel:
            accel.Set(accel.GetFlags(), accel.GetKeyCode(), menuItem.GetId())
            self._accelArray.append(accel)        
 
        self.UpdateRadioGroup(menuItem)
 
        return menuItem
 
 
    def GetMenuItemWidth(self, menuItem):
        """ Returns the width of a particular item. """
 
        menuItemWidth = 0
        text = menuItem.GetLabel() # Without accelerator
        accel = menuItem.GetAccelString()
 
        dc = wx.ClientDC(self)
 
        font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
        dc.SetFont(font)
 
        accelFiller = "XXXX"     # 4 spaces betweem text and accel column
 
        # Calc text length/height
        dummy, itemHeight = dc.GetTextExtent("Tp")
        width, height = dc.GetTextExtent(text)
        accelWidth, accelHeight = dc.GetTextExtent(accel)
        filler, dummy = dc.GetTextExtent(accelFiller)
 
        bmpHeight = bmpWidth = 0
 
        if menuItem.GetBitmap().Ok():
            bmpHeight = menuItem.GetBitmap().GetHeight()
            bmpWidth  = menuItem.GetBitmap().GetWidth()
 
        if itemHeight < self._marginHeight:
            itemHeight = self._marginHeight
 
        itemHeight = (bmpHeight > self._itemHeight and [bmpHeight] or [itemHeight])[0]
        itemHeight += 2*self._borderYWidth
 
        # Update the global menu item height if needed
        self._itemHeight = (self._itemHeight > itemHeight and [self._itemHeight] or [itemHeight])[0]
        self._marginWIdth = (self._marginWIdth > bmpWidth and [self._marginWIdth] or [bmpWidth])[0]
 
        # Update the accel width
        accelWidth += filler
        if accel:
            self._accelWidth = (self._accelWidth > accelWidth and [self._accelWidth] or [accelWidth])[0]
 
        # In case the item has image & is type radio or check, we need double size
        # left margin
        factor = (((menuItem.GetBitmap() != wx.NullBitmap) and \
                   (menuItem.IsCheckable() or (menuItem.GetKind() == wx.ITEM_RADIO))) and [2] or [1])[0]
 
        if factor == 2:
 
            self._imgMarginX = self._marginWIdth + 2*self._borderXWidth
            self._leftMarginWidth = 2 * self._marginWIdth + 2*self._borderXWidth
 
        else:
 
            self._leftMarginWidth = ((self._leftMarginWidth > self._marginWIdth + 2*self._borderXWidth) and \
                                    [self._leftMarginWidth] or [self._marginWIdth + 2*self._borderXWidth])[0]
 
        menuItemWidth = self.GetLeftMarginWidth() + 2*self.GetBorderXWidth() + width + self.GetRightMarginWidth()
        self._textX = self._imgMarginX + self._marginWIdth + self._textPadding
 
        # update the rightMargin X position
        self._rightMarginPosX = ((self._textX + width + self._accelWidth> self._rightMarginPosX) and \
                                 [self._textX + width + self._accelWidth] or [self._rightMarginPosX])[0]
 
        return menuItemWidth
 
 
    def GetMenuWidth(self):
        """ Returns the menu width. """
 
        return self._menuWidth
 
 
    def GetLeftMarginWidth(self):
        """ Returns the menu left margin width. """
 
        return self._leftMarginWidth
 
 
    def GetRightMarginWidth(self):
        """ Returns the menu right margin width. """
 
        return self._rightMarginWidth
 
 
    def GetBorderXWidth(self):
        """ Returns the menu border x-width. """
 
        return self._borderXWidth
 
 
    def GetBorderYWidth(self):
        """ Returns the menu border y-width. """
 
        return self._borderYWidth
 
 
    def GetItemHeight(self):
        """ Returns the height of a particular item. """
 
        return self._itemHeight
 
 
    def AppendCheckItem(self, id, item, helpString):
        """ Appends a wx.ITEM_CHECK item to this menu. """
 
        newItem = FlatMenuItem(self, id, item, helpString, wx.ITEM_CHECK)
        return self.AppendItem(newItem)
 
 
    def AppendRadioItem(self, id, item, helpString):
        """ Appends a wx.ITEM_RADIO item to this menu. """
 
        newItem = FlatMenuItem(self, id, item, helpString, wx.ITEM_RADIO)
        return self.AppendItem(newItem)
 
 
    def AppendSeparator(self):
        """ Appends a wx.ITEM_SEPARATOR item to this menu. """
 
        newItem = FlatMenuItem(self)
        return self.AppendItem(newItem)
 
 
    def Dismiss(self, dismissParent, resetOwner):
        """ Dismisses the popup window. """
 
        if self._activeWin:
 
            self._activeWin.PopEventHandler(True)
            self._activeWin = None
 
        if self._focusWin:
 
            self._focusWin.PopEventHandler(True)
            self._focusWin = None
 
        self._selectedItem = -1
 
        FlatMenuBase.Dismiss(self, dismissParent, resetOwner)
 
 
    def OnPaint(self, event):
        """ Handles the wx.EVT_PAINT event for FlatMenu. """
 
        dc = wx.PaintDC(self)
        self.DoDrawMenu(dc)
 
        # We need to redraw all our child menus
        self.RefreshChilds()
 
 
    def UpdateItem(self, item):
        """ Updates an item. """
 
        # notify menu bar that an item was modified directly
        if item and self._mb:
            self._mb.UpdateItem(item)
 
 
    def OnEraseBg(self, event):
        """ Handles the wx.EVT_ERASE_BACKGROUND event for FlatMenu. """
 
        pass
 
 
    def DoDrawMenu(self, dc):
        """ Actually draws the menu. """
 
        menuRect = self.GetMenuRect()
        menuBmp = wx.EmptyBitmap(menuRect.width, menuRect.height)
 
        mem_dc = wx.MemoryDC()
        mem_dc.SelectObject(menuBmp)
 
        # color the menu face with background color
        backColor = ArtManager.Get().GetMenuFaceColour()
        penColor  = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
 
        backBrush = wx.Brush(backColor)
        pen = wx.Pen(penColor)
 
        mem_dc.SetPen(pen)
        mem_dc.SetBrush(backBrush)
        mem_dc.DrawRectangleRect(menuRect)
 
        # draw items
        posy = 2
        nItems = len(self._itemsArr)
 
        # make all items as non-visible first
        for item in self._itemsArr:
            item.Show(False)
 
        visibleItems = 0
        screenHeight = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y)
 
        for nCount in xrange(nItems):
 
            visibleItems += 1        
            item = self._itemsArr[nCount]
            item.DrawSelf(mem_dc,           
                          posy,     
                          self._imgMarginX,
                          self._markerMarginX,
                          self._textX, 
                          self._rightMarginPosX,
                          nCount == self._selectedItem 
                          )
            posy += item.GetHeight()
            item.Show()
 
            # make sure we draw only visible items
            pp = self.ClientToScreen(wx.Point(0, posy))
 
            if pp.y > screenHeight:
                break
 
        if self._showScrollButtons:
            if self._upButton:
                self._upButton.Draw(mem_dc)
            if self._downButton:
                self._downButton.Draw(mem_dc)
 
        dc.Blit(0, 0, menuBmp.GetWidth(), menuBmp.GetHeight(), mem_dc, 0, 0)
 
 
    def DrawSelection(self, dc, oldSelection=-1):
        """ Redraws the menu. """
 
        self.Refresh()
 
 
    def RefreshChilds(self):
        """
        In some cases, we need to perform a recursive refresh for all opened submenu
        from this.
        """
 
        # Draw all childs menus of self menu as well
        child = self._openedSubMenu
        while child:
            dc = wx.ClientDC(child)
            child.DoDrawMenu(dc)
            child = child._openedSubMenu
 
 
    def DrawLeftMargin(self, dc, menuRect):
        """ Draws the menu left margin. """
 
        # Construct the margin rectangle
        marginRect = wx.Rect(menuRect.x+1, menuRect.y, self.GetLeftMarginWidth(), menuRect.height)
 
        # Set the gradient colors
        if Style2007 == ArtManager.Get().GetMenuTheme():
 
            dcsaver = DCSaver(dc)
            marginColor = ArtManager.Get().DarkColour(ArtManager.Get().GetMenuFaceColour(), 5)
            dc.SetPen(wx.Pen(marginColor))
            dc.SetBrush(wx.Brush(marginColor))
            dc.DrawRectangleRect(marginRect)
 
            dc.SetPen(wx.WHITE_PEN)
            dc.DrawLine(marginRect.x + marginRect.width, marginRect.y, marginRect.x + marginRect.width, marginRect.y + marginRect.height)
 
            borderColor = ArtManager.Get().DarkColour(ArtManager.Get().GetMenuFaceColour(), 10)
            dc.SetPen(wx.Pen(borderColor))
            dc.DrawLine(marginRect.x + marginRect.width-1, marginRect.y, marginRect.x + marginRect.width-1, marginRect.y + marginRect.height)
 
        else:
 
            startColor = ArtManager.Get().DarkColour(ArtManager.Get().GetMenuFaceColour(), 20)
            endColor   = ArtManager.Get().GetMenuFaceColour()
            ArtManager.Get().PaintStraightGradientBox(dc, marginRect, startColor, endColor, False)
 
 
    def GetMenuRect(self):
        """ Returns the menu rect. """
 
        clientRect = self.GetClientRect()
        return wx.Rect(clientRect.x, clientRect.y, clientRect.width, clientRect.height)
 
 
    def OnKeyDown(self, event):
        """ Handles the wx.EVT_KEY_DOWN event for FlatMenu. """
 
        self.OnChar(event.GetKeyCode())
 
 
    def OnChar(self, key):
        """ Handles key events for FlatMenu. """
 
        processed = True
 
        if key == wx.WXK_ESCAPE:
 
            if self._parentMenu:
                self._parentMenu.CloseSubMenu(-1)
            else:
                self.Dismiss(True, True)
 
        elif key == wx.WXK_LEFT:
 
            if self._parentMenu:
                # We are a submenu, dismiss us.
                self._parentMenu.CloseSubMenu(-1)
            else:               
                # try to find our root menu, if we are attached to menubar,
                # let it try and open the previous menu
                root = self.GetRootMenu()
                if root:
                    if root._mb:
                        root._mb.ActivatePreviousMenu()
 
        elif key == wx.WXK_RIGHT:
 
            if not self.TryOpenSubMenu(self._selectedItem, True):
                # try to find our root menu, if we are attached to menubar,
                # let it try and open the previous menu
                root = self.GetRootMenu()
                if root:
                    if root._mb:
                        root._mb.ActivateNextMenu()
 
        elif key == wx.WXK_UP:
            self.AdvanceSelection(False)
 
        elif key == wx.WXK_DOWN:
 
            self.AdvanceSelection()
 
        elif key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
            self.DoAction(self._selectedItem)
 
        elif key == wx.WXK_HOME:
 
            # Select first item of the menu
            if self._selectedItem != 0:
                oldSel = self._selectedItem
                self._selectedItem = 0
                dc = wx.ClientDC(self)
                self.DrawSelection(dc, oldSel)
 
        elif key == wx.WXK_END:
 
            # Select last item of the menu
            if self._selectedItem != len(self._itemsArr)-1:
                oldSel = self._selectedItem
                self._selectedItem = len(self._itemsArr)-1
                dc = wx.ClientDC(self)
                self.DrawSelection(dc, oldSel)
 
        elif key in [wx.WXK_CONTROL, wx.WXK_ALT]:
            # Alt was pressed
            root = self.GetRootMenu()
            root.Dismiss(False, True)
 
        else:
            try:
                chrkey = chr(key)
            except:
                return processed
 
            if chrkey.isalnum():
 
                ch = chrkey.lower()
 
                # Iterate over all the menu items 
                itemIdx = -1
                occur = 0
 
                for i in xrange(len(self._itemsArr)):
 
                    item = self._itemsArr[i]
                    mnemonic = item.GetMnemonicChar()
 
                    if mnemonic == ch:
 
                        if itemIdx == -1:
 
                            itemIdx = i
                            # We keep the index of only 
                            # the first occurence
 
                        occur += 1
 
                        # Keep on looping until no more items for self menu
 
                if itemIdx != -1:
 
                    if occur > 1:
 
                        # We select the first item
                        if self._selectedItem == itemIdx:
                            return processed
 
                        oldSel = self._selectedItem
                        self._selectedItem = itemIdx
                        dc = wx.ClientDC(self)
                        self.DrawSelection(dc, oldSel)
 
                    elif occur == 1:
 
                        # Activate the item, if self is a submenu item we first select it
                        item = self._itemsArr[itemIdx]
                        if item.IsSubMenu() and self._selectedItem != itemIdx:
 
                            oldSel = self._selectedItem
                            self._selectedItem = itemIdx
                            dc = wx.ClientDC(self)
                            self.DrawSelection(dc, oldSel)
 
                        self.DoAction(itemIdx)
 
                else:
 
                    processed = False
 
        return processed
 
 
    def AdvanceSelection(self, down=True):
        """ Advance forward or backward the current selection. """
 
        # make sure we have at least two items in the menu (which are not 
        # separators)
        num=0
        singleItemIdx = -1
 
        for i in xrange(len(self._itemsArr)):
 
            item = self._itemsArr[i]
            if item.IsSeparator():
                continue
            num += 1
            singleItemIdx = i
 
        if num < 1:
            return
 
        if num == 1: 
            # Select the current one
            self._selectedItem = singleItemIdx
            dc = wx.ClientDC(self)
            self.DrawSelection(dc, -1)
            return
 
        oldSelection = self._selectedItem
 
        if not down:
 
            # find the next valid item
            while 1:
 
                self._selectedItem -= 1
                if self._selectedItem < 0:
                    self._selectedItem = len(self._itemsArr)-1
                if not self._itemsArr[self._selectedItem].IsSeparator():
                    break
 
        else:
 
            # find the next valid item
            while 1:
 
                self._selectedItem += 1
                if self._selectedItem > len(self._itemsArr)-1:
                    self._selectedItem = 0
                if not self._itemsArr[self._selectedItem].IsSeparator():
                    break
 
        dc = wx.ClientDC(self)
        self.DrawSelection(dc, oldSelection)
 
 
    def HitTest(self, pos):
        """ HitTest method for FlatMenu. """
 
        if self._showScrollButtons:
 
            if self._upButton and self._upButton.GetClientRect().Contains(pos):
                return MENU_HT_SCROLL_UP, -1
 
            if self._downButton and self._downButton.GetClientRect().Contains(pos):
                return MENU_HT_SCROLL_DOWN, -1
 
        for ii, item in enumerate(self._itemsArr):
 
            if item.GetRect().Contains(pos) and item.IsEnabled() and item.IsShown():
                return MENU_HT_ITEM, ii
 
        return MENU_HT_NONE, -1
 
 
    def OnMouseMove(self, event):
        """ Handles the wx.EVT_MOTION event for FlatMenu. """
 
        if "__WXMSW__" in wx.Platform:
            # Ignore dummy mouse move events
            pt = wx.GetMousePosition()
            if self._mousePtAtStartup == pt:
                return
 
        pos = event.GetPosition()
 
        # we need to ignore extra mouse events: example when this happens is when
        # the mouse is on the menu and we open a submenu from keyboard - Windows
        # then sends us a dummy mouse move event, we (correctly) determine that it
        # happens in the parent menu and so immediately close the just opened
        # submenunot
 
        if "__WXMSW__" in wx.Platform:
 
            ptCur = self.ClientToScreen(pos)
            if ptCur == self._ptLast:
                return
 
            self._ptLast = ptCur
 
        # first let the scrollbar handle it
        self.TryScrollButtons(event)
        self.ProcessMouseMove(pos)
 
 
    def OnMouseLeftDown(self, event):
        """ Handles the wx.EVT_LEFT_DOWN event for FlatMenu. """
 
        if self.TryScrollButtons(event):
            return
 
        pos = event.GetPosition()
        self.ProcessMouseLClick(pos)
 
 
    def OnMouseLeftUp(self, event):
        """ Handles the wx.EVT_LEFT_UP event for FlatMenu. """
 
        if self.TryScrollButtons(event):
            return
 
        pos = event.GetPosition()
        rect = self.GetClientRect()
 
        if not rect.Contains(pos):
 
            # The event is not in our coords, 
            # so we try our parent
            win = self._parentMenu
 
            while win:
 
                # we need to translate our client coords to the client coords of the
                # window we forward this event to
                ptScreen = self.ClientToScreen(pos)
                p = win.ScreenToClient(ptScreen)
 
                if win.GetClientRect().Contains(p):
 
                    event.m_x = p.x
                    event.m_y = p.y
                    win.OnMouseLeftUp(event)
                    return
 
                else:
                    # try the grandparent
                    win = win._parentMenu
 
        if self._showScrollButtons:
 
            if self._upButton:
                self._upButton.ProcessLeftUp(pos)
            if self._downButton:
                self._downButton.ProcessLeftUp(pos)
 
 
    def OnMouseRightDown(self, event):
        """ Handles the wx.EVT_RIGHT_DOWN event for FlatMenu. """
 
        if self.TryScrollButtons(event):
            return
 
        pos = event.GetPosition()
        self.ProcessMouseRClick(pos)
 
 
    def ProcessMouseRClick(self, pos):
        """ Processes mouse right clicks. """
 
        rect = self.GetClientRect()
 
        if not rect.Contains(pos):
 
            # The event is not in our coords, 
            # so we try our parent
 
            win = self._parentMenu
            while win:
 
                # we need to translate our client coords to the client coords of the
                # window we forward self event to
                ptScreen = self.ClientToScreen(pos)
                p = win.ScreenToClient(ptScreen)
 
                if win.GetClientRect().Contains(p):
                    win.ProcessMouseRClick(p)
                    return
 
                else:
                    # try the grandparent
                    win = win._parentMenu
 
            # At this point we can assume that the event was not 
            # processed, so we dismiss the menu and its children
            self.Dismiss(True, True)
            return
 
        # else: we do nothing ...
 
 
    def ProcessMouseLClick(self, pos):
        """ Processes mouse left clicks. """
 
        rect = self.GetClientRect()
 
        if not rect.Contains(pos):
 
            # The event is not in our coords, 
            # so we try our parent
 
            win = self._parentMenu
            while win:
 
                # we need to translate our client coords to the client coords of the
                # window we forward self event to
                ptScreen = self.ClientToScreen(pos)
                p = win.ScreenToClient(ptScreen)
 
                if win.GetClientRect().Contains(p):                
                    win.ProcessMouseLClick(p)
                    return
 
                else:
                    # try the grandparent
                    win = win._parentMenu
 
            # At this point we can assume that the event was not 
            # processed, so we dismiss the menu and its children
            self.Dismiss(True, True)
            return
 
 
        # test if we are on a menu item
 
        res, itemIdx = self.HitTest(pos)
 
        if res == MENU_HT_ITEM:
            self.DoAction(itemIdx)
 
        elif res == MENU_HT_SCROLL_UP:
            if self._upButton:
                self._upButton.ProcessLeftDown(pos)
 
        elif res == MENU_HT_SCROLL_DOWN:
            if self._downButton:
                self._downButton.ProcessLeftDown(pos)
 
        else:
            self._selectedItem = -1
 
 
    def ProcessMouseMove(self, pos):
        """ Processes mouse movements. """
 
        rect = self.GetClientRect()
 
        if not rect.Contains(pos):
 
            # The event is not in our coords, 
            # so we try our parent
 
            win = self._parentMenu
            while win:
 
                # we need to translate our client coords to the client coords of the
                # window we forward self event to
                ptScreen = self.ClientToScreen(pos)
                p = win.ScreenToClient(ptScreen)
 
                if win.GetClientRect().Contains(p):
                    win.ProcessMouseMove(p)
                    return
 
                else:
                    # try the grandparent
                    win = win._parentMenu
 
            # If we are attached to a menu bar, 
            # let him process the event as well
            if self._mb:
 
                ptScreen = self.ClientToScreen(pos)
                p = self._mb.ScreenToClient(ptScreen)
 
                if self._mb.GetClientRect().Contains(p):
 
                    # let the menu bar process it
                    self._mb.ProcessMouseMoveFromMenu(p)
                    return
 
            return
 
        # test if we are on a menu item
        res, itemIdx = self.HitTest(pos)
 
        if res == MENU_HT_SCROLL_DOWN:
 
            if self._downButton:
                self._downButton.ProcessMouseMove(pos)
 
        elif res == MENU_HT_SCROLL_UP:
 
            if self._upButton:
                self._upButton.ProcessMouseMove(pos)
 
        elif res == MENU_HT_ITEM:
 
            if self._downButton:
                self._downButton.ProcessMouseMove(pos)
 
            if self._upButton:
                self._upButton.ProcessMouseMove(pos)
 
            if self._selectedItem == itemIdx:
                return
 
            oldSelection = self._selectedItem
            self._selectedItem = itemIdx
            self.CloseSubMenu(self._selectedItem)           
 
            dc = wx.ClientDC(self)
            self.DrawSelection(dc, oldSelection)
 
            self.TryOpenSubMenu(self._selectedItem)
 
        else:
 
            oldSelection = self._selectedItem
            self._selectedItem = -1
            dc = wx.ClientDC(self)
            self.DrawSelection(dc, oldSelection)
 
 
    def OnMouseLeaveWindow(self, event):
        """ Handles the wx.EVT_LEAVE_WINDOW event for FlatMenu. """
 
        if self._clearCurrentSelection:
 
            oldSelection = self._selectedItem
            self._selectedItem = -1
            dc = wx.ClientDC(self)
            self.DrawSelection(dc, oldSelection)
 
        self._clearCurrentSelection = True
 
        if "__WXMSW__" in wx.Platform:
            self.SetCursor(self._oldCur)
 
 
    def OnMouseEnterWindow(self, event):
        """ Handles the wx.EVT_ENTER_WINDOW event for FlatMenu. """
 
        if "__WXMSW__" in wx.Platform:
            self._oldCur = self.GetCursor()
            self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
 
        event.Skip()
 
 
    def OnKillFocus(self, event):
        """ Handles the wx.EVT_KILL_FOCUS event for FlatMenu. """
 
        self.Dismiss(True, True)
 
 
    def CloseSubMenu(self, itemIdx):
        """ Close a child sub-menu. """
 
        item = None
        subMenu = None
 
        if itemIdx >= 0 and itemIdx < len(self._itemsArr):
            item = self._itemsArr[itemIdx]
 
        # Close sub-menu first
        if item:
            subMenu = item.GetSubMenu()
 
        if self._openedSubMenu and self._openedSubMenu != subMenu:
 
            # We have another sub-menu open, close it 
            self._openedSubMenu.Dismiss(False, True)
            self._openedSubMenu = None
 
 
    def DoAction(self, itemIdx):
        """ Performs an action based on user selection. """
 
        if itemIdx < 0 or itemIdx >= len(self._itemsArr):
            raise "Invalid menu item"
            return
 
        item = self._itemsArr[itemIdx]
 
        if not item.IsEnabled() or item.IsSeparator():
            return
 
        # Close sub-menu if needed
        self.CloseSubMenu(itemIdx)
 
        if item.IsSubMenu() and not item.GetSubMenu().IsShown():
 
            # Popup child menu
            self.TryOpenSubMenu(itemIdx)
            return
 
        if item.IsRadioItem():
            # if the radio item is already checked, 
            # just send command event. Else, check it, uncheck the current
            # checked item in the radio item group, and send command event
            if not item.IsChecked():
                item._groupPtr.SetSelection(item)
 
        elif item.IsCheckable():
 
            item.Check(not item.IsChecked())
            dc = wx.ClientDC(self)
            self.DrawSelection(dc)
 
        if not item.IsSubMenu():
 
            self.Dismiss(True, False)
 
            # Send command event
            self.SendCmdEvent(itemIdx)
 
 
    def TryOpenSubMenu(self, itemIdx, selectFirst=False):
        """ If itemIdx is an item with submenu, open it. """
 
        if itemIdx < 0 or itemIdx >= len(self._itemsArr):
            return False
 
        item = self._itemsArr[itemIdx]
        if item.IsSubMenu() and not item.GetSubMenu().IsShown():
 
            pos = wx.Point()
 
            # Popup child menu
            pos.x = item.GetRect().GetWidth()+ item.GetRect().GetX()-5
            pos.y = item.GetRect().GetY()
            self._clearCurrentSelection = False
            self._openedSubMenu = item.GetSubMenu()
            item.GetSubMenu().Popup(pos, self._owner, self)
 
            # Select the first child
            if selectFirst:
 
                dc = wx.ClientDC(item.GetSubMenu())
                item.GetSubMenu()._selectedItem = 0
                item.GetSubMenu().DrawSelection(dc)
 
            return True
 
        return False
 
 
    def _RemoveById(self, id):
        """ Used internally. """
 
        # First we search for the menu item (recursivley)
        menuParent = None
        item = None
        idx = wx.NOT_FOUND
        idx, menuParent = self.FindMenuItemPos(id)
 
        if idx != wx.NOT_FOUND:
 
            # Remove the menu item
            item = menuParent._itemsArr[idx]
            menuParent._itemsArr.pop(idx)
 
            # update group
            if item._groupPtr and item.IsRadioItem():
                item._groupPtr.Remove(item)
 
            # Resize the menu
            menuParent.ResizeMenu()
 
        return item
 
 
    def Remove(self, item):
        """ Removes an item from the menu. """
 
        if type(item) != type(1):
            item = item.GetId()
 
        return self._RemoveById(item)
 
 
    def _DestroyById(self, id):
        """ Used internally. """
 
        item = None
        item = self.Remove(id)
 
        if item:
            del item
 
 
    def Destroy(self, item):
        """ Destroys an item from the menu. """
 
        if type(item) != type(1):
            item = item.GetId()
 
        self._DestroyById(item)
 
 
    def Insert(self, pos, id, item, helpString="", kind=wx.ITEM_NORMAL):
        """ Inserts an item into the menu. """
 
        newitem = FlatMenuItem(self, id, item, helpString, kind)
        return self.InsertItem(pos, newitem)
 
 
    def InsertItem(self, pos, item):
        """ Inserts an item into the menu. """
 
        if pos == len(self._itemsArr):
            # Append it
            return self.AppendItem(item)
 
        # Insert the menu item 
        self._itemsArr.insert(pos, item)
        item._isAttachedToMenu = True
 
        # Recalcualte the menu gemotry
        self.ResizeMenu()
 
        # Update radio groups
        self.UpdateRadioGroup(item)
 
        return item
 
 
    def UpdateRadioGroup(self, item):
        """ Updates a group of radio items. """
 
        if item.IsRadioItem():
 
            # Udpate radio groups in case this item is a radio item
            sibling = self.GetSiblingGroupItem(item)
            if sibling:
 
                item._groupPtr = sibling._groupPtr
                item._groupPtr.Add(item)
 
                if item.IsChecked():
 
                    item._groupPtr.SetSelection(item)
 
            else:
 
                # first item in group
                item._groupPtr = FlatMenuItemGroup()
                item._groupPtr.Add(item)
                item._groupPtr.SetSelection(item)
 
 
    def ResizeMenu(self):
        """ Resizes the menu to the correct size. """
 
        # can we do the resize?
        if not self._resizeMenu:
            return
 
        items = self._itemsArr
        self._itemsArr = []
 
        # Clear accelerator table
        self._accelArray = []
 
        # Reset parameters and menu size
        self._menuWidth =  2*self._marginWIdth
        self._imgMarginX = 0
        self._markerMarginX = 0
        self._textX = self._marginWIdth
        self._rightMarginPosX = -1
        self._itemHeight = self._marginHeight
        self.SetSize(wx.Size(self._menuWidth, self._itemHeight+4))
 
        # Now we simply add the items 
        for item in items:
            self.AppendItem(item)
 
 
    def FindItem(self, itemId, menu=None):
        """ Finds an item inside the menu based on its id. """
 
        idx = wx.NOT_FOUND
 
        if menu:
 
            idx, menu = self.FindMenuItemPos(itemId, menu)
            if idx != wx.NOT_FOUND:
                return menu._itemsArr[idx]
            else:
                return None
 
        else:
 
            idx, parentMenu = self.FindMenuItemPos(itemId, None)
            if idx != wx.NOT_FOUND:
                return parentMenu._itemsArr[idx]
            else:
                return None
 
 
    def FindMenuItemPos(self, itemId, menu=None):
        """ Finds an item and its position inside the menu based on its id. """
 
        menu = None
        item = None
 
        idx = wx.NOT_FOUND
 
        for i in xrange(len(self._itemsArr)):
 
            item = self._itemsArr[i]
 
            if item.GetId() == itemId:
 
                menu = self
                idx = i
                break
 
            elif item.IsSubMenu():
 
                idx, menu = item.GetSubMenu().FindMenuItemPos(itemId, menu)
                if idx != wx.NOT_FOUND:
                    break
 
            else:
 
                item = None
 
        return idx, menu
 
 
    def GetAccelTable(self):
        """ Returns the menu accelerator table. """
 
        n = len(self._accelArray)
        if n == 0:
            return wx.NullAcceleratorTable
 
        entries = [wx.AcceleratorEntry() for ii in xrange(n)]
 
        for counter in len(entries):
            entries[counter] = self._accelArray[counter]
 
        table = wx.AcceleratorTable(entries)
        del entries
 
        return table
 
 
    def GetAccelArray(self):
 
        return self._accelArray
 
 
    # events 
    def SendCmdEvent(self, itemIdx):
        """ Actually sends menu command events. """
 
        if itemIdx < 0 or itemIdx >= len(self._itemsArr):
            raise "Invalid menu item"
            return
 
        item = self._itemsArr[itemIdx]
 
        # Create the event
        event = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, item.GetId())
 
        # For checkable item, set the IsChecked() value
        if item.IsCheckable():
            event.SetInt((item.IsChecked() and [1] or [0])[0])
 
        event.SetEventObject(self)
 
        if self._owner:
            self._owner.GetEventHandler().ProcessEvent(event)
        else:
            self.GetEventHandler().ProcessEvent(event)
 
 
    def SendUIEvent(self, itemIdx):
        """ Actually sends menu UI events. """
 
        if itemIdx < 0 or itemIdx >= len(self._itemsArr):
            raise "Invalid menu item"
            return
 
        item = self._itemsArr[itemIdx]
        event = wx.UpdateUIEvent(item.GetId())
 
        event.Check(item.IsChecked())
        event.Enable(item.IsEnabled())
        event.SetText(item.GetText())
        event.SetEventObject(self)
 
        if self._owner:
            self._owner.GetEventHandler().ProcessEvent(event)
        else:
            self.GetEventHandler().ProcessEvent(event)
 
        item.Check(event.GetChecked()) 
        item.SetLabel(event.GetText())
        item.Enable(event.GetEnabled())
        self.ResizeMenu()
 
 
    def Clear(self):
        """ Clears the menu items. """
 
        # since Destroy() call ResizeMenu(), we turn this flag on
        # to avoid resizing the menu for every item removed
        self._resizeMenu = False
 
        lenItems = len(self._itemsArr)
        for ii in xrange(lenItems):
            self.Destroy(self._itemsArr[0].GetId())
 
        # Now we can resize the menu
        self._resizeMenu = True
        self.ResizeMenu()
 
 
    def FindMenuItemPosSimple(self, item):
        """ Finds an item and its position inside the menu based on its id. """
 
        if item == None or len(self._itemsArr) == 0:
            return wx.NOT_FOUND
 
        for i in xrange(len(self._itemsArr)):
            if self._itemsArr[i] == item:
                return i
 
        return wx.NOT_FOUND
 
 
    def GetAllItems(self, menu=None, items=[]):
        """ Internal function to help recurse thru all over the menu items. """
 
        # first copy the current menu items
        newitems = [item for item in items]
 
        if not menu:
            return newitems
 
        # if any item in this menu has sub-menu, copy them as well
        for i in xrange(len(menu._itemsArr)):
            if menu._itemsArr[i].IsSubMenu():
                newitems = self.GetAllItems(menu._itemsArr[i].GetSubMenu(), newitems)
 
        return newitems
 
 
    def GetSiblingGroupItem(self, item):
        """ Used internally. """
 
        pos = self.FindMenuItemPosSimple(item)
        if pos in [wx.NOT_FOUND, 0]:
            return None
 
        if self._itemsArr[pos-1].IsRadioItem():
            return self._itemsArr[pos-1]
 
        return None
 
 
    def ScrollDown(self):
        """ Scrolls the menu down (for very tall menus). """
 
        # increase the self._from index
        if not self._itemsArr[-1].IsShown():        
            self._first += 1
            self.Refresh()
 
            return True
 
        else:
            if self._downButton:
                self._downButton.GetTimer().Stop()
 
            return False
 
 
    def ScrollUp(self):
        """ Scrolls the menu up (for very tall menus). """
 
        if self._first == 0:
            if self._upButton:
                self._upButton.GetTimer().Stop()
 
            return False
 
        else:
 
            self._first -= 1
            self.Refresh()
            return True
 
 
    # Not used anymore
    def TryScrollButtons(self, event):
        """ Used internally. """
 
        return False
 
 
    def OnTimer(self, event):
        """ Handles the wx.EVT_TIMER event for FlatMenu. """
 
        if self._upButton and self._upButton.GetTimerId() == event.GetId():
 
            self.ScrollUp()
 
        elif self._downButton and self._downButton.GetTimerId() == event.GetId():
 
            self.ScrollDown()
 
        else:
 
            event.Skip()
 
 
#--------------------------------------------------------
# Class MenuKbdRedirector
#--------------------------------------------------------
 
class MenuKbdRedirector(wx.EvtHandler):
    """ A keyboard event handler. """
 
    def __init__(self, menu, oldHandler):
        """ Default class constructor. """
 
        self._oldHandler = oldHandler
        self.SetMenu(menu)
        wx.EvtHandler.__init__(self)
 
 
    def SetMenu(self, menu):
        """ Sets the listened menu. """
 
        self._menu = menu
 
 
    def ProcessEvent(self, event):
        """ Processes the inout event. """
 
        if event.GetEventType() in [wx.EVT_KEY_DOWN, wx.EVT_CHAR, wx.EVT_CHAR_HOOK]:
            return self._menu.OnChar(event.GetKeyCode())
        else:
            return self._oldHandler.ProcessEvent(event)
 
 
#--------------------------------------------------------
# Class FocusHandler
#--------------------------------------------------------
 
class FocusHandler(wx.EvtHandler):
    """ A focus event handler. """
 
    def __init__(self, menu):
        """ Default class constructor. """
 
        wx.EvtHandler.__init__(self)
        self.SetMenu(menu)
 
        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
 
 
    def SetMenu(self, menu):
        """ Sets the listened menu. """
 
        self._menu = menu
 
 
    def OnKeyDown(self, event):
        """ Handles the wx.EVT_KEY_DOWN event for FocusHandler. """
 
        # Let parent process it
        self._menu.OnKeyDown(event)
 
 
    def OnKillFocus(self, event):
        """ Handles the wx.EVT_KILL_FOCUS event for FocusHandler. """
 
        wx.PostEvent(self._menu, event)