Source code for enaml.wx.wx_menu_bar

#------------------------------------------------------------------------------
#  Copyright (c) 2012, Enthought, Inc.
#  All rights reserved.
#------------------------------------------------------------------------------
import wx

from .wx_menu import WxMenu, EVT_MENU_CHANGED
from .wx_widget import WxWidget


class wxMenuBar(wx.MenuBar):
    """ A wx.MenuBar subclass which exposes a more convenient api for
    working with wxMenu children.

    """
    def __init__(self, *args, **kwargs):
        """ Initialize a wxMenuBar.

        Parameters
        ----------
        *args, **kwargs
            The positional and keyword arguments needed to initialize
            a wx.MenuBar.

        """
        super(wxMenuBar, self).__init__(*args, **kwargs)
        self._menus = []
        self._visible_menus = []
        self._enabled = True

    #--------------------------------------------------------------------------
    # Private API
    #--------------------------------------------------------------------------
    def OnMenuChanged(self, event):
        """ The event handler for the EVT_MENU_CHANGED event.

        This event handler will synchronize the menu changes with
        the menu bar.

        """
        event.Skip()
        if self.IsAttached():
            menu = event.GetEventObject()

            # First, check for a visibility change. This requires adding
            # or removing the menu from the menu bar.
            visible = menu.IsVisible()
            was_visible = menu in self._visible_menus
            if visible != was_visible:
                if visible:
                    index = self._menus.index(menu)
                    index = min(index, len(self._visible_menus))
                    self._visible_menus.insert(index, menu)
                    self.Insert(index, menu, menu.GetTitle())
                    self.EnableTop(index, menu.IsEnabled())
                else:
                    index = self._visible_menus.index(menu)
                    self._visible_menus.pop(index)
                    self.Remove(index)
                return

            # If the menu isn't visible, there's nothing to do.
            if not visible:
                return

            # For all other state, the menu can be updated in-place.
            index = self._visible_menus.index(menu)
            self.SetMenuLabel(index, menu.GetTitle())
            self.EnableTop(index, menu.IsEnabled())

    #--------------------------------------------------------------------------
    # Public API
    #--------------------------------------------------------------------------
    def IsEnabled(self):
        """ Get whether or not the menu bar is enabled.

        Returns
        -------
        result : bool
            Whether or not the menu bar is enabled.

        """
        return self._enabled

    def SetEnabled(self, enabled):
        """ Set whether or not the menu bar is enabled.

        Parameters
        ----------
        enabled : bool
            Whether or not the menu bar is enabled.

        """
        # Wx does not provide a means for disabling the entire menu
        # bar, so we must do it manually by disabling each menu.
        if self._enabled != enabled:
            self._enabled = enabled
            for menu in self._menus:
                menu._SetBarEnabled(enabled)

    def AddMenu(self, menu):
        """ Add a wxMenu to the menu bar.

        If the menu already exists in the menu bar, this is a no-op.

        Parameters
        ----------
        menu : wxMenu
            The wxMenu instance to add to the menu bar.

        """
        self.InsertMenu(None, menu)

    def InsertMenu(self, before, menu):
        """ Insert a wxMenu into the menu bar.

        If the menu already exists in the menu bar, this is a no-op.

        Parameters
        ----------
        before : wxMenu
            The menu before which to insert the given menu.

        menu : wxMenu
            The menu to insert into the menu bar.

        """
        menus = self._menus
        if menu not in menus:
            if before in menus:
                index = menus.index(before)
            else:
                index = len(menus)
            menus.insert(index, menu)
            if menu.IsVisible():
                max_index = len(self._visible_menus)
                index = min(index, max_index)
                self._visible_menus.insert(index, menu)
                self.Insert(index, menu, menu.GetTitle())
            menu.Bind(EVT_MENU_CHANGED, self.OnMenuChanged)
            menu._SetBarEnabled(self._enabled)

    def RemoveMenu(self, menu):
        """ Remove a wxMenu from the menu bar.

        If the menu does not exist in the menu bar, this is a no-op.

        Parameters
        ----------
        menu : wxMenu
            The menu to remove from the menu bar.

        """
        menus = self._menus
        if menu in menus:
            menus.remove(menu)
            menu.Unbind(EVT_MENU_CHANGED, handler=self.OnMenuChanged)
            visible_menus = self._visible_menus
            if menu in visible_menus:
                index = visible_menus.index(menu)
                visible_menus.remove(menu)
                self.Remove(index)

    def Update(self):
        """ A method which can be called to update the menu bar.

        Calling this method will manually refresh the state of the
        items in the menu bar. This is useful to call just after
        attaching the menu bar to a frame, since the menu bar state
        cannot be updated prior to being attached.

        """
        if self.IsAttached():
            for index, menu in enumerate(self._visible_menus):
                self.SetMenuLabel(index, menu.GetTitle())
                if not menu.IsEnabled():
                    self.EnableTop(index, False)


[docs]class WxMenuBar(WxWidget): """ A Wx implementation of an Enaml MenuBar. """ #-------------------------------------------------------------------------- # Setup Methods #--------------------------------------------------------------------------
[docs] def create_widget(self, parent, tree): """ Create the underlying menu bar widget. """ return wxMenuBar()
[docs] def init_layout(self): """ Initialize the layout for the underlying control. """ super(WxMenuBar, self).init_layout() widget = self.widget() for child in self.children(): if isinstance(child, WxMenu): widget.AddMenu(child.widget()) #-------------------------------------------------------------------------- # Child Events #--------------------------------------------------------------------------
[docs] def child_removed(self, child): """ Handle the child removed event for a WxMenuBar. """ if isinstance(child, WxMenu): self.widget().RemoveMenu(child.widget())
[docs] def child_added(self, child): """ Handle the child added event for a WxMenuBar. """ if isinstance(child, WxMenu): before = self.find_next_menu(child) self.widget().InsertMenu(before, child.widget()) #-------------------------------------------------------------------------- # Utility Methods #--------------------------------------------------------------------------
[docs] def find_next_menu(self, child): """ Get the wxMenu instance which comes immediately after the menu of the given child. Parameters ---------- child : WxMenu The child menu of interest. Returns ------- result : wxMenu or None The wxMenu which comes immediately after the menu of the given child, or None if no menu follows the child. """ index = self.index_of(child) if index != -1: for child in self.children()[index + 1:]: if isinstance(child, WxMenu): return child.widget() #-------------------------------------------------------------------------- # Widget Update Methods #--------------------------------------------------------------------------
[docs] def set_enabled(self, enabled): """ Overridden parent class method. This properly sets the enabled state on a menu bar. """ self.widget().SetEnabled(enabled)
[docs] def set_visible(self, visible): """ Overrdden parent class method. This method is a no-op, since a MenuBar cannot change it's visibility under Wx. """ pass