diff --git a/enaml/wx/__init__.py b/enaml/wx/__init__.py deleted file mode 100644 index 0bc6ead48..000000000 --- a/enaml/wx/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ diff --git a/enaml/wx/wx_abstract_button.py b/enaml/wx/wx_abstract_button.py deleted file mode 100644 index e0d02cd6a..000000000 --- a/enaml/wx/wx_abstract_button.py +++ /dev/null @@ -1,123 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -from atom.api import Int - -from enaml.widgets.abstract_button import ProxyAbstractButton - -from .wx_control import WxControl - - -# cyclic notification guard flags -CHECKED_GUARD = 0x1 - - -class WxAbstractButton(WxControl, ProxyAbstractButton): - """ A Wx implementation of an Enaml ProxyAbstractButton. - - This class can serve as a base class for widgets that implement - button behavior such as CheckBox, RadioButton and PushButtons. - It is not meant to be used directly. - - """ - #: Cyclic notification guard. This a bitfield of multiple guards. - _guard = Int(0) - - #-------------------------------------------------------------------------- - # Setup Methods - #-------------------------------------------------------------------------- - def create_widget(self): - """ Implement in a subclass to create the widget. - - """ - raise NotImplementedError - - def init_widget(self): - """ Initialize the button widget. - - """ - super(WxAbstractButton, self).init_widget() - d = self.declaration - if d.text: - self.set_text(d.text) - self.set_checkable(d.checkable) - self.set_checked(d.checked) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_clicked(self, event): - """ The event handler for the clicked event. - - Parameters - ---------- - event : wxEvent - The wx event object. This is ignored by the handler. - - """ - if not self._guard & CHECKED_GUARD: - checked = self.get_checked() - self.declaration.checked = checked - self.declaration.clicked(checked) - - def on_toggled(self, event): - """ The event handler for the toggled event. - - Parameters - ---------- - event : wxEvent - The wx event object. This is ignored by the handler. - - """ - if not self._guard & CHECKED_GUARD: - checked = self.get_checked() - self.declaration.checked = checked - self.declaration.toggled(checked) - - #-------------------------------------------------------------------------- - # ProxyAbstractButton API - #-------------------------------------------------------------------------- - def set_text(self, text): - """ Sets the widget's text with the provided value. - - """ - with self.geometry_guard(): - self.widget.SetLabel(text) - - def set_icon(self, icon): - """ Sets the widget's icon to the provided image - - This is not supported on wx. - - """ - pass - - def set_icon_size(self, icon_size): - """ Sets the widget's icon size to the provided tuple - - This is not supported on wx. - - """ - pass - - def set_checkable(self, checkable): - """ Sets whether or not the widget is checkable. - - """ - raise NotImplementedError - - def get_checked(self): - """ Returns the checked state of the widget. - - """ - raise NotImplementedError - - def set_checked(self, checked): - """ Sets the widget's checked state with the provided value. - - """ - raise NotImplementedError diff --git a/enaml/wx/wx_action.py b/enaml/wx/wx_action.py deleted file mode 100644 index 6e206d7b5..000000000 --- a/enaml/wx/wx_action.py +++ /dev/null @@ -1,530 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -from weakref import WeakValueDictionary - -import wx -import wx.lib.newevent - -from atom.api import Int, Typed - -from enaml.widgets.action import ProxyAction - -from .wx_toolkit_object import WxToolkitObject - - -#: An event emitted when a wxAction has been triggered by the user. The -#: payload of the event will have an 'IsChecked' attribute. -wxActionTriggeredEvent, EVT_ACTION_TRIGGERED = wx.lib.newevent.NewEvent() - -#: An event emitted by a wxAction when it has been toggled by the user. -#: The payload of the event will have an 'IsChecked' attribute. -wxActionToggledEvent, EVT_ACTION_TOGGLED = wx.lib.newevent.NewEvent() - -#: An event emitted by a wxAction when its state has been changed. -wxActionChangedEvent, EVT_ACTION_CHANGED = wx.lib.newevent.NewEvent() - - -class wxAction(wx.EvtHandler): - """ A wx.EvtHandler which behaves similar to a QAction. - - """ - #: Class storage which maps action id -> action instance. - _action_map = WeakValueDictionary() - - @classmethod - def FindById(cls, action_id): - """ Find a wxAction instance using the given action id. - - Parameters - ---------- - action_id : int - The id for the action. - - Returns - ------- - result : wxAction or None - The wxAction instance for the given id, or None if not - action exists for that id. - - """ - return cls._action_map.get(action_id) - - def __init__(self, parent=None): - """ Initialize a wxAction. - - Parameters - ---------- - parent : object or None - The parent for this wxAction. The parent is not directly - used by the action, but is provided as a convenience for - other parts of the framework. - - """ - super(wxAction, self).__init__() - self._parent = parent - self._text = u'' - self._tool_tip = u'' - self._status_tip = u'' - self._checkable = False - self._checked = False - self._enabled = True - self._visible = True - self._group_enabled = True - self._group_visible = True - self._separator = False - self._batch = False - self._id = wx.NewId() - self._action_map[self._id] = self - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def _EmitChanged(self): - """ Emits the EVT_ACTION_CHANGED event if not in batch mode. - - """ - if not self._batch: - event = wxActionChangedEvent() - event.SetEventObject(self) - wx.PostEvent(self, event) - - def _SetGroupEnabled(self, enabled): - """ A private method called by an owner action group. - - Parameters - ---------- - enabled : bool - Whether or not the owner group is enabled. - - """ - if self._group_enabled != enabled: - old = self.IsEnabled() - self._group_enabled = enabled - new = self.IsEnabled() - if old != new: - self._EmitChanged() - - def _SetGroupVisible(self, visible): - """ A private method called by an owner action group. - - Parameters - ---------- - visible : bool - Whether or not the owner group is visble. - - """ - if self._group_visible != visible: - old = self.IsVisible() - self._group_visible = visible - new = self.IsVisible() - if old != new: - self._EmitChanged() - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def GetParent(self): - """ Get the parent of the action. - - Returns - ------- - result : object or None - The parent of this action or None. - - """ - return self._parent - - def SetParent(self, parent): - """ Set the parent of the action. - - Parameters - ---------- - parent : object or None - The object to use as the parent of this action. - - """ - self._parent = parent - - def Trigger(self): - """ A method called by the action owner when the user triggers - the action. - - This handler will emit the custom EVT_ACTION_TRIGGERED event. - User code should not typically call this method directly. - - """ - # This event is dispatched immediately in order to preserve - # the order of event firing for trigger/toggle. - event = wxActionTriggeredEvent(IsChecked=self._checked) - event.SetEventObject(self) - wx.PostEvent(self, event) - - def BeginBatch(self): - """ Enter batch update mode for the action. - - """ - self._batch = True - - def EndBatch(self, emit=True): - """ Exit batch update mode for the action. - - Parameters - ---------- - emit : bool, optional - If True, emit a changed event after leaving batch mode. The - default is True. - - """ - self._batch = False - if emit: - self._EmitChanged() - - def GetId(self): - """ Get the unique wx id for this action. - - Returns - ------- - result : int - The wx id number for this action. - - """ - return self._id - - def GetText(self): - """ Get the text for the action. - - Returns - ------- - result : unicode - The unicode text for the action. - - """ - return self._text - - def SetText(self, text): - """ Set the text for the action. - - Parameters - ---------- - text : unicode - The unicode text for the action. - - """ - if self._text != text: - self._text = text - self._EmitChanged() - - def GetToolTip(self): - """ Get the tool tip for the action. - - Returns - ------- - result : unicode - The unicode tool tip for the action. - - """ - return self._tool_tip - - def SetToolTip(self, tool_tip): - """ Set the tool tip for the action. - - Parameters - ---------- - tool_tip : unicode - The unicode tool tip for the action. - - """ - if self._tool_tip != tool_tip: - self._tool_tip = tool_tip - self._EmitChanged() - - def GetStatusTip(self): - """ Get the status tip for the action. - - Returns - ------- - result : unicode - The unicode status tip for the action. - - """ - return self._status_tip - - def SetStatusTip(self, status_tip): - """ Set the status tip for the action. - - Parameters - ---------- - status_tip : unicode - The unicode status tip for the action. - - """ - if self._status_tip != status_tip: - self._status_tip = status_tip - self._EmitChanged() - - def IsCheckable(self): - """ Get whether or not the action is checkable. - - Returns - ------- - result : bool - Whether or not the action is checkable. - - """ - return self._checkable - - def SetCheckable(self, checkable): - """ Set whether or not the action is checkable. - - Parameters - ---------- - checkable : bool - Whether or not the action is checkable. - - """ - if self._checkable != checkable: - self._checkable = checkable - self._EmitChanged() - - def IsChecked(self): - """ Get whether or not the action is checked. - - Returns - ------- - result : bool - Whether or not the action is checked. - - """ - return self._checked - - def SetChecked(self, checked): - """ Set whether or not the action is checked. - - Parameters - ---------- - checked : bool - Whether or not the action is checked. - - """ - if self._checked != checked: - self._checked = checked - self._EmitChanged() - event = wxActionToggledEvent(IsChecked=checked) - event.SetEventObject(self) - wx.PostEvent(self, event) - - def IsEnabled(self): - """ Get whether or not the action is enabled. - - Returns - ------- - result : bool - Whether or not the action is enabled. - - """ - if self._group_enabled: - return self._enabled - return False - - def SetEnabled(self, enabled): - """ Set whether or not the action is enabled. - - Parameters - ---------- - enabled : bool - Whether or not the action is enabled. - - """ - if self._enabled != enabled: - self._enabled = enabled - if self._group_enabled: - self._EmitChanged() - - def IsVisible(self): - """ Get whether or not the action is visible. - - Returns - ------- - result : bool - Whether or not the action is visible. - - """ - if self._group_visible: - return self._visible - return False - - def SetVisible(self, visible): - """ Set whether or not the action is visible. - - Parameters - ---------- - visible : bool - Whether or not the action is visible. - - """ - if self._visible != visible: - self._visible = visible - if self._group_visible: - self._EmitChanged() - - def IsSeparator(self): - """ Get whether or not the action is a separator. - - Returns - ------- - result : bool - Whether or not the action is a separator. - - """ - return self._separator - - def SetSeparator(self, separator): - """ Set whether or not the action is a separator. - - Parameters - ---------- - separator : bool - Whether or not the action is a separator. - - """ - if self._separator != separator: - self._separator = separator - self._EmitChanged() - - -# cyclic notification guard flags -CHECKED_GUARD = 0x1 - - -class WxAction(WxToolkitObject, ProxyAction): - """ A Wx implementation of an Enaml ProxyAction. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxAction) - - #: Cyclic notification guard. This a bitfield of multiple guards. - _guard = Int(0) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying wxAction object. - - """ - self.widget = wxAction(self.parent_widget()) - - def init_widget(self): - """ Create and initialize the underlying control. - - """ - super(WxAction, self).init_widget() - d = self.declaration - widget = self.widget - widget.BeginBatch() - if d.text: - self.set_text(d.text) - if d.tool_tip: - self.set_tool_tip(d.tool_tip) - if d.status_tip: - self.set_status_tip(d.status_tip) - if d.icon: - self.set_icon(d.icon) - self.set_checkable(d.checkable) - self.set_checked(d.checked) - self.set_enabled(d.enabled) - self.set_visible(d.visible) - self.set_separator(d.separator) - widget.EndBatch(emit=False) - widget.Bind(EVT_ACTION_TRIGGERED, self.on_triggered) - widget.Bind(EVT_ACTION_TOGGLED, self.on_toggled) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_triggered(self, event): - """ The event handler for the EVT_ACTION_TRIGGERED event. - - """ - if not self._guard & CHECKED_GUARD: - checked = event.IsChecked - self.declaration.checked = checked - self.declaration.triggered(checked) - - def on_toggled(self, event): - """ The event handler for the EVT_ACTION_TOGGLED event. - - """ - if not self._guard & CHECKED_GUARD: - checked = event.IsChecked - self.declaration.checked = checked - self.declaration.toggled(checked) - - #-------------------------------------------------------------------------- - # ProxyAction API - #-------------------------------------------------------------------------- - def set_text(self, text): - """ Set the text on the underlying control. - - """ - self.widget.SetText(text) - - def set_tool_tip(self, tool_tip): - """ Set the tool tip on the underlying control. - - """ - self.widget.SetToolTip(tool_tip) - - def set_status_tip(self, status_tip): - """ Set the status tip on the underyling control. - - """ - self.widget.SetStatusTip(status_tip) - - def set_icon(self, icon): - """ Set the icon for the action. - - This is not supported on Wx. - - """ - pass - - def set_checkable(self, checkable): - """ Set the checkable state on the underlying control. - - """ - self.widget.SetCheckable(checkable) - - def set_checked(self, checked): - """ Set the checked state on the underlying control. - - """ - self._guard |= CHECKED_GUARD - try: - self.widget.SetChecked(checked) - finally: - self._guard &= ~CHECKED_GUARD - - def set_enabled(self, enabled): - """ Set the enabled state on the underlying control. - - """ - self.widget.SetEnabled(enabled) - - def set_visible(self, visible): - """ Set the visible state on the underlying control. - - """ - self.widget.SetVisible(visible) - - def set_separator(self, separator): - """ Set the separator state on the underlying control. - - """ - self.widget.SetSeparator(separator) diff --git a/enaml/wx/wx_action_group.py b/enaml/wx/wx_action_group.py deleted file mode 100644 index 37b08e77b..000000000 --- a/enaml/wx/wx_action_group.py +++ /dev/null @@ -1,366 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.action_group import ProxyActionGroup - -from .wx_action import WxAction, EVT_ACTION_CHANGED -from .wx_toolkit_object import WxToolkitObject - - -class wxActionGroup(wx.EvtHandler): - """ A simple object which keeps track of a group of actions. - - """ - def __init__(self, parent=None): - """ Initialize a wxActionGroup. - - Parameters - ---------- - parent : object or None - The parent for this wxActionGroup. The parent is not used - directly by the action, but is provided as a convenience - for other parts of the framework. - - """ - super(wxActionGroup, self).__init__() - self._parent = parent - self._exclusive = True - self._enabled = True - self._visible = True - self._actions = [] - self._checked_action = None - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def OnActionChanged(self, event): - """ The event handler for the EVT_ACTION_CHANGED event. - - This handler will update the current checked action and toggle - any other old action if the group is exclusive. - - """ - event.Skip() - action = event.GetEventObject() - if action.IsChecked(): - old_action = self._checked_action - self._checked_action = action - if self.IsExclusive(): - if action is not old_action: - if old_action is not None: - old_action.SetChecked(False) - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def GetParent(self): - """ Get the parent of the action group. - - Returns - ------- - result : object or None - The parent of this action group or None. - - """ - return self._parent - - def SetParent(self, parent): - """ Set the parent of the action group. - - Parameters - ---------- - parent : object or None - The object to use as the parent of this action group. - - """ - self._parent = parent - - def AddAction(self, action): - """ Add an action to the action group. - - If the action already exists in the group, this is a no-op. - - Parameters - ---------- - action : wxAction - The wxAction to add to the group. - - """ - actions = self._actions - if action not in actions: - actions.append(action) - action.Bind(EVT_ACTION_CHANGED, self.OnActionChanged) - parent = action.GetParent() - if isinstance(parent, wxActionGroup) and parent is not self: - parent.RemoveAction(action) - action.SetParent(self) - - if action.IsChecked(): - old_action = self._checked_action - self._checked_action = action - if self.IsExclusive(): - if action is not old_action: - if old_action is not None: - old_action.SetChecked(False) - - action._SetGroupEnabled(self._enabled) - action._SetGroupVisible(self._visible) - - def RemoveAction(self, action): - """ Remove the action from the action group. - - If the action does not exist in the group, this is a no-op. - - Parameters - ---------- - action : wxAction - The wxAction to remove from the group. - - """ - actions = self._actions - if action in actions: - actions.remove(action) - action.Unbind(EVT_ACTION_CHANGED, handler=self.OnActionChanged) - if action is self._checked_action: - self._checked_action = None - - def GetActions(self): - """ Get the list of actions for this group. - - Returns - ------- - result : list - The list of wxAction instances for this action group. This - list should not be modified in-place. - - """ - return self._actions - - def GetCheckedAction(self): - """ Get the currently checked action in the group. - - Returns - ------- - result : wxAction or None - The currently checked action in the group, or None if - no action is checked. - - """ - return self._checked_action - - def IsExclusive(self): - """ Get whether or not the action group is exclusive. - - Returns - ------- - result : bool - Whether or not the action group is exclusive. - - """ - return self._exclusive - - def SetExclusive(self, exclusive): - """ Set whether or not the action group is exclusive. - - Parameters - ---------- - exclusive : bool - Whether or not the action is exclusive. - - """ - if self._exclusive != exclusive: - self._exclusive = exclusive - if exclusive: - curr = self._checked_action - for action in self._actions: - if action is not curr: - action.SetChecked(False) - - def IsEnabled(self): - """ Get whether or not the action group is enabled. - - Returns - ------- - result : bool - Whether or not the action group is enabled. - - """ - return self._enabled - - def SetEnabled(self, enabled): - """ Set whether or not the action group is enabled. - - Parameters - ---------- - enabled : bool - Whether or not the action group is enabled. - - """ - if self._enabled != enabled: - self._enabled = enabled - for action in self._actions: - action._SetGroupEnabled(enabled) - - def IsVisible(self): - """ Get whether or not the action group is visible. - - Returns - ------- - result : bool - Whether or not the action group is visible. - - """ - return self._visible - - def SetVisible(self, visible): - """ Set whether or not the action group is visible. - - Parameters - ---------- - enabled : bool - Whether or not the action is visible. - - """ - if self._visible != visible: - self._visible = visible - for action in self._actions: - action._SetGroupVisible(visible) - - -class WxActionGroup(WxToolkitObject, ProxyActionGroup): - """ A Wx implementation of an Enaml ProxyActionGroup. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxActionGroup) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying action group widget. - - """ - self.widget = wxActionGroup(self.parent_widget()) - - def init_widget(self): - """ Initialize the control. - - """ - super(WxActionGroup, self).init_widget() - d = self.declaration - self.set_exclusive(d.exclusive) - self.set_enabled(d.enabled) - self.set_visible(d.visible) - - def init_layout(self): - """ Initialize the layout for the control. - - """ - super(WxActionGroup, self).init_layout() - widget = self.widget - for action in self.actions(): - widget.AddAction(action) - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def find_next_action(self, child): - """ Locate the wxAction object which logically follows the child. - - If the given child is last in the list of children, then the - parent object will be invoked to find the wxAction which follows - this action group. - - Parameters - ---------- - child : QtToolkitObject - The child object of interest. - - Returns - ------- - result : wxAction or None - The wxAction which logically follows the position of the - child in the list of children. None will be returned if - a relevant QAction is not found. - - """ - found = False - for dchild in self.children(): - if found and isinstance(dchild, WxAction): - return dchild.widget - else: - found = child is dchild - parent = self.parent() - if parent is not None: - return parent.find_next_action(self) - - def child_added(self, child): - """ Handle the child added event for a WxActionGroup. - - """ - super(WxActionGroup, self).child_added(child) - if isinstance(child, WxAction): - self.widget.AddAction(child.widget) - parent = self.parent() - if parent is not None: - before = self.find_next_action(child) - parent.widget.InsertAction(before, child.widget) - - def child_removed(self, child): - """ Handle the child removed event for a WxActionGroup. - - """ - super(WxActionGroup, self).child_removed(child) - if isinstance(child, WxAction) and child.widget is not None: - self.widget.RemoveAction(child.widget) - parent = self.parent() - if parent is not None: - parent.widget.RemoveAction(child.widget) - - #-------------------------------------------------------------------------- - # Utility Methods - #-------------------------------------------------------------------------- - def actions(self): - """ Get the WxAction children for this action group. - - Returns - ------- - result : list - The list of wxAction instances which are children of this - action group. Unlike the list returned by the `GetActions` - method of the wxActionGroup, the children in this list will - have the correct order. - - """ - isinst = isinstance - return [c.widget for c in self.children() if isinst(c, WxAction)] - - #-------------------------------------------------------------------------- - # ProxyActionGroup API - #-------------------------------------------------------------------------- - def set_exclusive(self, exclusive): - """ Set the exclusive state of the underlying control. - - """ - self.widget.SetExclusive(exclusive) - - def set_enabled(self, enabled): - """ Set the enabled state of the underlying control. - - """ - self.widget.SetEnabled(enabled) - - def set_visible(self, visible): - """ Set the visible state of the underlying control. - - """ - self.widget.SetVisible(visible) diff --git a/enaml/wx/wx_application.py b/enaml/wx/wx_application.py deleted file mode 100644 index 01c7d781c..000000000 --- a/enaml/wx/wx_application.py +++ /dev/null @@ -1,100 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.application import Application, ProxyResolver - -from .wx_deferred_caller import DeferredCall, TimedCall -from .wx_factories import WX_FACTORIES - - -class WxApplication(Application): - """ A Wx implementation of an Enaml application. - - A WxApplication uses the Wx toolkit to implement an Enaml UI that - runs in the local process. - - """ - #: The private QApplication instance. - _wxapp = Typed(wx.App) - - def __init__(self): - """ Initialize a WxApplication. - - """ - super(WxApplication, self).__init__() - self._wxapp = wx.GetApp() or wx.PySimpleApp() - self.resolver = ProxyResolver(factories=WX_FACTORIES) - - #-------------------------------------------------------------------------- - # Abstract API Implementation - #-------------------------------------------------------------------------- - def start(self): - """ Start the application's main event loop. - - """ - app = self._wxapp - if not app.IsMainLoopRunning(): - app.MainLoop() - - def stop(self): - """ Stop the application's main event loop. - - """ - app = self._wxapp - if app.IsMainLoopRunning(): - app.Exit() - - def deferred_call(self, callback, *args, **kwargs): - """ Invoke a callable on the next cycle of the main event loop - thread. - - Parameters - ---------- - callback : callable - The callable object to execute at some point in the future. - - *args, **kwargs - Any additional positional and keyword arguments to pass to - the callback. - - """ - DeferredCall(callback, *args, **kwargs) - - def timed_call(self, ms, callback, *args, **kwargs): - """ Invoke a callable on the main event loop thread at a - specified time in the future. - - Parameters - ---------- - ms : int - The time to delay, in milliseconds, before executing the - callable. - - callback : callable - The callable object to execute at some point in the future. - - *args, **kwargs - Any additional positional and keyword arguments to pass to - the callback. - - """ - TimedCall(ms, callback, *args, **kwargs) - - def is_main_thread(self): - """ Indicates whether the caller is on the main gui thread. - - Returns - ------- - result : bool - True if called from the main gui thread. False otherwise. - - """ - return wx.Thread_IsMain() diff --git a/enaml/wx/wx_bounded_date.py b/enaml/wx/wx_bounded_date.py deleted file mode 100644 index b9a043aa3..000000000 --- a/enaml/wx/wx_bounded_date.py +++ /dev/null @@ -1,129 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import datetime - -import wx - -from atom.api import Int - -from enaml.widgets.bounded_date import ProxyBoundedDate - -from .wx_control import WxControl - - -def as_wx_date(py_date): - """ Convert an iso date string to a wxDateTime. - - """ - day = py_date.day - month = py_date.month - 1 # wx peculiarity! - year = py_date.year - return wx.DateTimeFromDMY(day, month, year) - - -def as_py_date(wx_date): - """ Convert a QDate object into and iso date string. - - """ - day = wx_date.GetDay() - month = wx_date.GetMonth() + 1 # wx peculiarity! - year = wx_date.GetYear() - return datetime.date(year, month, day) - - -# cyclic notification guard flags -CHANGED_GUARD = 0x1 - - -class WxBoundedDate(WxControl, ProxyBoundedDate): - """ A base class for use with Wx widgets implementing behavior - for subclasses of BoundedDate. - - """ - #: Cyclic notification guard. This a bitfield of multiple guards. - _guard = Int(0) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Implement in a subclass to create the date widget. - - """ - raise NotImplementedError - - def init_widget(self): - """ Create and initialize the bounded date widget. - - """ - super(WxBoundedDate, self).init_widget() - d = self.declaration - self.set_minimum(d.minimum) - self.set_maximum(d.maximum) - self.set_date(d.date) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_date_changed(self, event): - """ An event handler to connect to the date changed signal of - the underlying widget. - - This will convert the wxDateTime to iso format and send the Enaml - widget the 'date_changed' action. - - """ - if not self._guard & CHANGED_GUARD: - self.declaration.date = self.get_date() - - #-------------------------------------------------------------------------- - # Abstract Methods and ProxyBoundedDate API - #-------------------------------------------------------------------------- - def get_date(self): - """ Return the current date in the control. - - Returns - ------- - result : date - The current control date as a date object. - - """ - raise NotImplementedError - - def set_minimum(self, date): - """ Set the widget's minimum date. - - Parameters - ---------- - date : date - The date object to use for setting the minimum date. - - """ - raise NotImplementedError - - def set_maximum(self, date): - """ Set the widget's maximum date. - - Parameters - ---------- - date : date - The date object to use for setting the maximum date. - - """ - raise NotImplementedError - - def set_date(self, date): - """ Set the widget's current date. - - Parameters - ---------- - date : date - The date object to use for setting the date. - - """ - raise NotImplementedError diff --git a/enaml/wx/wx_calendar.py b/enaml/wx/wx_calendar.py deleted file mode 100644 index 220014ccd..000000000 --- a/enaml/wx/wx_calendar.py +++ /dev/null @@ -1,91 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -from wx.calendar import CalendarCtrl, EVT_CALENDAR - -from atom.api import Typed - -from enaml.widgets.calendar import ProxyCalendar - -from .wx_bounded_date import ( - WxBoundedDate, CHANGED_GUARD, as_wx_date, as_py_date -) - - -class WxCalendar(WxBoundedDate, ProxyCalendar): - """ A Wx implementation of an Enaml ProxyCalendar. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(CalendarCtrl) - - #-------------------------------------------------------------------------- - # Initialization - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the calender widget. - - """ - self.widget = CalendarCtrl(self.parent_widget()) - - def init_widget(self): - """ Initialize the widget. - - """ - super(WxCalendar, self).init_widget() - self.widget.Bind(EVT_CALENDAR, self.on_date_changed) - - #-------------------------------------------------------------------------- - # Abstract Method Implementation - #-------------------------------------------------------------------------- - def get_date(self): - """ Return the current date in the control. - - Returns - ------- - result : date - The current control date as a Python date object. - - """ - return as_py_date(self.widget.GetDate()) - - def set_minimum(self, date): - """ Set the widget's minimum date. - - Parameters - ---------- - date : date - The date object to use for setting the minimum date. - - """ - self.widget.SetLowerDateLimit(as_wx_date(date)) - - def set_maximum(self, date): - """ Set the widget's maximum date. - - Parameters - ---------- - date : date - The date object to use for setting the maximum date. - - """ - self.widget.SetUpperDateLimit(as_wx_date(date)) - - def set_date(self, date): - """ Set the widget's current date. - - Parameters - ---------- - date : date - The date object to use for setting the date. - - """ - self._guard |= CHANGED_GUARD - try: - self.widget.SetDate(as_wx_date(date)) - finally: - self._guard &= ~CHANGED_GUARD diff --git a/enaml/wx/wx_check_box.py b/enaml/wx/wx_check_box.py deleted file mode 100644 index 9879dbbe9..000000000 --- a/enaml/wx/wx_check_box.py +++ /dev/null @@ -1,138 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx -import wx.lib.newevent - -from atom.api import Typed - -from enaml.widgets.check_box import ProxyCheckBox - -from .wx_abstract_button import WxAbstractButton, CHECKED_GUARD - - -#: A check box event emitted when the button is clicked. -wxCheckBoxClicked, EVT_CHECKBOX_CLICKED = wx.lib.newevent.NewEvent() - -#: A check event emitted when the button value is changed. -wxCheckBoxToggled, EVT_CHECKBOX_TOGGLED = wx.lib.newevent.NewEvent() - - -class wxProperCheckBox(wx.CheckBox): - """ A custom subclass of wx.CheckBox. - - This checkbox emits an EVT_CHECKBOX_CLICKED event whenever the - button is clicked. It also emits an EVT_CHECKBOX_TOGGLED whenever - the checkbox changes state. - - """ - def __init__(self, *args, **kwargs): - """ Initialize a wxProperCheckBox. - - *args, **kwargs - The positional and keyword arguments required to initialize - a wx.RadioButton. - - """ - super(wxProperCheckBox, self).__init__(*args, **kwargs) - self._in_click = False - self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) - self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) - self.Bind(wx.EVT_CHECKBOX, self.OnToggled) - - def OnLeftDown(self, event): - """ Handles the left down mouse event for the check box. - - This is first part of generating a click event. - - """ - event.Skip() - self._in_click = True - - def OnLeftUp(self, event): - """ Handles the left up mouse event for the check box. - - This is the second part of generating a click event. - - """ - event.Skip() - if self._in_click: - self._in_click = False - event = wxCheckBoxClicked() - wx.PostEvent(self, event) - - def OnToggled(self, event): - """ Handles the standard toggle event and emits the custom - toggle event for the check box. - - """ - event = wxCheckBoxToggled() - wx.PostEvent(self, event) - - def SetValue(self, val): - """ Overrides the default SetValue method to emit proper events. - - """ - old = self.GetValue() - if old != val: - super(wxProperCheckBox, self).SetValue(val) - self._last = val - event = wxCheckBoxToggled() - wx.PostEvent(self, event) - - -class WxCheckBox(WxAbstractButton, ProxyCheckBox): - """ A Wx implementation of an Enaml ProxyCheckBox. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxProperCheckBox) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying check box widget. - - """ - self.widget = wxProperCheckBox(self.parent_widget()) - - def init_widget(self): - """ Create and initialize the check box control. - - """ - super(WxCheckBox, self).init_widget() - widget = self.widget - widget.Bind(EVT_CHECKBOX_CLICKED, self.on_clicked) - widget.Bind(EVT_CHECKBOX_TOGGLED, self.on_toggled) - - #-------------------------------------------------------------------------- - # Abstract API Implementation - #-------------------------------------------------------------------------- - def set_checkable(self, checkable): - """ Sets whether or not the widget is checkable. - - This is not supported in Wx. - - """ - pass - - def get_checked(self): - """ Returns the checked state of the widget. - - """ - return self.widget.GetValue() - - def set_checked(self, checked): - """ Sets the widget's checked state with the provided value. - - """ - self._guard |= CHECKED_GUARD - try: - self.widget.SetValue(checked) - finally: - self._guard &= ~CHECKED_GUARD diff --git a/enaml/wx/wx_combo_box.py b/enaml/wx/wx_combo_box.py deleted file mode 100644 index ba42719d1..000000000 --- a/enaml/wx/wx_combo_box.py +++ /dev/null @@ -1,89 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Int, Typed - -from enaml.widgets.combo_box import ProxyComboBox - -from .wx_control import WxControl - - -# cyclic notification guard flags -INDEX_GUARD = 0x1 - - -class WxComboBox(WxControl, ProxyComboBox): - """ A Wx implementation of an Enaml ProxyComboBox. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wx.ComboBox) - - #: Cyclic notification guard. This a bitfield of multiple guards. - _guard = Int(0) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the QComboBox widget. - - """ - self.widget = wx.ComboBox(self.parent_widget(), style=wx.CB_READONLY) - - def init_widget(self): - """ Create and initialize the underlying widget. - - """ - super(WxComboBox, self).init_widget() - d = self.declaration - self.set_items(d.items) - self.set_index(d.index) - self.set_editable(d.editable) - self.widget.Bind(wx.EVT_COMBOBOX, self.on_index_changed) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_index_changed(self, event): - """ The signal handler for the index changed signal. - - """ - if not self._guard & INDEX_GUARD: - self.declaration.index = self.widget.GetCurrentSelection() - - #-------------------------------------------------------------------------- - # ProxyComboBox API - #-------------------------------------------------------------------------- - def set_items(self, items): - """ Set the items of the ComboBox. - - """ - widget = self.widget - sel = widget.GetCurrentSelection() - widget.SetItems(items) - widget.SetSelection(sel) - - def set_index(self, index): - """ Set the current index of the ComboBox - - """ - self._guard |= INDEX_GUARD - try: - self.widget.SetSelection(index) - finally: - self._guard &= ~INDEX_GUARD - - def set_editable(self, editable): - """ Set whether the combo box is editable. - - This is not supported on wx. - - """ - pass diff --git a/enaml/wx/wx_constraints_widget.py b/enaml/wx/wx_constraints_widget.py deleted file mode 100644 index 2b720a316..000000000 --- a/enaml/wx/wx_constraints_widget.py +++ /dev/null @@ -1,107 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -from contextlib import contextmanager - -from atom.api import Int, ForwardTyped - -from enaml.widgets.constraints_widget import ProxyConstraintsWidget - -from .wx_widget import WxWidget - - -# keep around for backwards compatibility -def size_hint_guard(obj): - return obj.geometry_guard() - - -def WxContainer(): - from .wx_container import WxContainer - return WxContainer - - -class WxConstraintsWidget(WxWidget, ProxyConstraintsWidget): - """ A Wx implementation of an Enaml ProxyConstraintsWidget. - - """ - #: The container which manages the layout for this widget. This - #: is assigned during the layout building pass. - layout_container = ForwardTyped(WxContainer) - - #: The layout index for this widget's layout item. This is assigned - #: during the layout building pass. - layout_index = Int() - - def destroy(self): - """ A reimplemented destructor. - - This destructor drops the reference to the layout container. - - """ - del self.layout_container - super(WxConstraintsWidget, self).destroy() - - #-------------------------------------------------------------------------- - # ProxyConstraintsWidget API - #-------------------------------------------------------------------------- - def request_relayout(self): - """ Request a relayout of the proxy widget. - - This method forwards the request to the layout container. - - """ - container = self.layout_container - if container is not None: - container.request_relayout() - - #-------------------------------------------------------------------------- - # Layout API - #-------------------------------------------------------------------------- - def geometry_updated(self): - """ Notify the layout system that the geometry has changed. - - This method forwards the update to the layout container. - - """ - container = self.layout_container - if container is not None: - container.geometry_updated(self) - self.post_wx_layout_request() - - @contextmanager - def geometry_guard(self): - """ A context manager for guarding the geometry of the widget. - - If the proxy is fully active, this context manager will call the - 'geometry_updated' method if the size hint, minimum, or maximum - size of the widget changes during context execution. - - """ - if not self.is_active: - yield - return - widget = self.widget - old_hint = widget.GetBestSize() - old_min = widget.GetMinSize() - old_max = widget.GetMaxSize() - yield - if (old_hint != widget.GetBestSize() or - old_min != widget.GetMinSize() or - old_max != widget.GetMaxSize()): - self.geometry_updated() - - #-------------------------------------------------------------------------- - # Reimplementations - #-------------------------------------------------------------------------- - def set_font(self, font): - """ A reimplemented font setter. - - This method sets the font from within a geometry guard. - - """ - with self.geometry_guard(): - super(WxConstraintsWidget, self).set_font(font) diff --git a/enaml/wx/wx_container.py b/enaml/wx/wx_container.py deleted file mode 100644 index 6ee30d420..000000000 --- a/enaml/wx/wx_container.py +++ /dev/null @@ -1,634 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -from collections import deque -from contextlib import contextmanager - -import wx - -from atom.api import Atom, Bool, Callable, Float, Typed - -from enaml.layout.layout_manager import LayoutItem, LayoutManager -from enaml.widgets.constraints_widget import ConstraintsWidget -from enaml.widgets.container import ProxyContainer - -from .wx_constraints_widget import WxConstraintsWidget -from .wx_frame import WxFrame - - -# Commonly used default sizes -DEFAULT_BEST_SIZE = wx.Size(-1, -1) -DEFAULT_MIN_SIZE = wx.Size(0, 0) -DEFAULT_MAX_SIZE = wx.Size(16777215, 16777215) - - -class LayoutPoint(Atom): - """ A class which represents a point in layout space. - - """ - #: The x-coordinate of the point. - x = Float(0.0) - - #: The y-coordinate of the point. - y = Float(0.0) - - -class WxLayoutItem(LayoutItem): - """ A concrete LayoutItem implementation for a WxConstraintsWidget. - - """ - #: The constraints widget declaration object for the layout item. - declaration = Typed(ConstraintsWidget) - - #: The underlying widget for the layout item. - widget = Typed(wx.Window) - - #: The layout point which represents the offset of the parent item - #: from the origin of the root item. - offset = Typed(LayoutPoint) - - #: The layout point which represents the offset of this item from - #: the offset of the root item. - origin = Typed(LayoutPoint) - - def constrainable(self): - """ Get a reference to the underlying constrainable object. - - Returns - ------- - result : Constrainable - An object which implements the Constrainable interface. - - """ - return self.declaration - - def margins(self): - """ Get the margins for the underlying widget. - - Returns - ------- - result : tuple - An empty tuple as constraints widgets do not have margins. - - """ - return () - - def size_hint(self): - """ Get the size hint for the underlying widget. - - Returns - ------- - result : tuple - A 2-tuple of numbers representing the (width, height) - size hint of the widget. - - """ - hint = self.widget.GetBestSize() - return (hint.width, hint.height) - - def min_size(self): - """ Get the minimum size for the underlying widget. - - Returns - ------- - result : tuple - A 2-tuple of numbers representing the (width, height) - min size of the widget. If any value is less than zero, - constraints will not be generated for that dimension. - - """ - min_size = self.widget.GetMinSize() - if min_size != DEFAULT_MIN_SIZE: - return (min_size.width, min_size.height) - return (-1, -1) - - def max_size(self): - """ Get the maximum size for the underlying widget. - - Returns - ------- - result : tuple - A 2-tuple of numbers representing the (width, height) - max size of the widget. If any value is less than zero, - constraints will not be generated for that dimension. - - """ - max_size = self.widget.GetMaxSize() - if max_size != DEFAULT_MAX_SIZE: - return (max_size.width, max_size.height) - return (-1, -1) - - def constraints(self): - """ Get the user-defined constraints for the item. - - Returns - ------- - result : list - The list of user-defined constraints. - - """ - return self.declaration.layout_constraints() - - def set_geometry(self, x, y, width, height): - """ Set the geometry of the underlying widget. - - Parameters - ---------- - x : float - The new value for the x-origin of the widget. - - y : float - The new value for the y-origin of the widget. - - width : float - The new value for the width of the widget. - - height : float - The new value for the height of the widget. - - """ - origin = self.origin - origin.x = x - origin.y = y - offset = self.offset - x -= offset.x - y -= offset.y - self.widget.SetDimensions(x, y, width, height) - - -class WxContainerItem(WxLayoutItem): - """ A WxLayoutItem subclass which handles container margins. - - """ - #: A callable used to get the container widget margins. - margins_func = Callable() - - def margins(self): - """ Get the margins for the underlying widget. - - Returns - ------- - result : tuple - A 4-tuple of ints representing the container margins. - - """ - a, b, c, d = self.declaration.padding - e, f, g, h = self.margins_func(self.widget) - return (a + e, b + f, c + g, d + h) - - -class WxSharedContainerItem(WxContainerItem): - """ A WxContainerItem subclass which works for shared containers. - - """ - def size_hint_constraints(self): - """ Get the size hint constraints for the item. - - A shared container does not generate size hint constraints. - - """ - return [] - - -class WxChildContainerItem(WxLayoutItem): - """ A WxLayoutItem subclass which works for child containers. - - """ - def constraints(self): - """ Get the user constraints for the item. - - A child container does not expose its user defined constraints - to the parent container. - - """ - return [] - - def min_size(self): - """ Get the minimum size for the underlying widget. - - The min size for a child container lives on the proxy object. - The widget limits must be bypassed for child container. - - """ - min_size = self.declaration.proxy.min_size - if min_size != DEFAULT_MIN_SIZE: - return (min_size.width, min_size.height) - return (-1, -1) - - def max_size(self): - """ Get the maximum size for the underlying widget. - - The max size for a child container lives on the proxy object. - The widget limits must be bypassed for child container. - - """ - max_size = self.declaration.proxy.max_size - if max_size != DEFAULT_MAX_SIZE: - return (max_size.width, max_size.height) - return (-1, -1) - - -class wxContainer(wx.PyPanel): - """ A subclass of wx.PyPanel which allows the default best size to - be overriden by calling SetBestSize. - - This functionality is used by the WxContainer to override the - size hint with a value computed from the constraints layout - manager. - - """ - #: An invalid wx.Size used as the default value for class instances. - _best_size = wx.Size(-1, -1) - - def DoGetBestSize(self): - """ Reimplemented parent class method. - - This will return the best size as set by a call to SetBestSize. - If that is invalid, then the superclass' version will be used. - - """ - size = self._best_size - if not size.IsFullySpecified(): - size = super(wxContainer, self).DoGetBestSize() - return size - - def SetBestSize(self, size): - """ Sets the best size to use for this container. - - """ - self._best_size = size - - -class wxLayoutTimer(wx.Timer): - """ A custom wx Timer which for collapsing layout requests. - - """ - def __init__(self, owner): - super(wxLayoutTimer, self).__init__() - self.owner = owner - - def Notify(self): - self.owner._on_relayout_timer() - - -class WxContainer(WxFrame, ProxyContainer): - """ A Wx implementation of an Enaml ProxyContainer. - - """ - #: A reference to the toolkit widget created by the proxy. - widget = Typed(wxContainer) - - #: The minimum size of the container as computed by the layout - #: manager. This will be updated on every relayout pass and is - #: used by the WxChildContainerItem to generate size constraints. - min_size = Typed(wx.Size) - - #: The maximum size of the container as computed by the layout - #: manager. This will be updated on every relayout pass and is - #: used by the WxChildContainerItem to generate size constraints. - max_size = Typed(wx.Size) - - #: A timer used to collapse relayout requests. The timer is created - #: on an as needed basis and destroyed when it is no longer needed. - _layout_timer = Typed(wxLayoutTimer) - - #: The layout manager which handles the system of constraints. - _layout_manager = Typed(LayoutManager) - - #: Whether or not the current container is shown. This is toggled - #: by the EVT_SHOW handler. - _is_shown = Bool(True) - - def destroy(self): - """ A reimplemented destructor. - - This destructor clears the layout timer and layout manager - so that any potential reference cycles are broken. - - """ - timer = self._layout_timer - if timer is not None: - timer.Stop() - del self._layout_timer - del self._layout_manager - super(WxContainer, self).destroy() - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Creates the QContainer widget. - - """ - self.widget = wxContainer(self.parent_widget()) - - def init_layout(self): - """ Initialize the layout of the widget. - - """ - super(WxContainer, self).init_layout() - self._setup_manager() - self._update_size_bounds() - self._update_geometries() - widget = self.widget - widget.Bind(wx.EVT_SIZE, self._on_resized) - widget.Bind(wx.EVT_SHOW, self._on_shown) - - #-------------------------------------------------------------------------- - # Layout API - #-------------------------------------------------------------------------- - def request_relayout(self): - """ Request a relayout of the container. - - """ - # If this container owns the layout, (re)start the timer. The - # list of layout items is reset to prevent an edge case where - # a parent container layout occurs before the child container, - # causing the child to resize potentially deleted widgets which - # still have strong refs in the layout items list. - manager = self._layout_manager - if manager is not None: - if self._layout_timer is None: - manager.clear_items() - self.widget.Freeze() - self._layout_timer = wxLayoutTimer(self) - self._layout_timer.Start(1, oneShot=True) - return - - # If an ancestor container owns the layout, proxy the call. - container = self.layout_container - if container is not None: - container.request_relayout() - - def geometry_updated(self, item=None): - """ Notify the layout system that the geometry has changed. - - Parameters - ---------- - item : WxConstraintsWidget, optional - The constraints widget with the updated geometry. If this - is None, it indicates that this container's geometry is - the one which has changed. - - """ - # If this container's geometry has changed and it has an ancestor - # layout container, notify that container since it cares about - # this container's geometry. If the layout for this container is - # shared, the layout item will take care of supplying the proper - # list geometry constraints. - container = self.layout_container - if item is None: - if container is not None: - container.geometry_updated(self) - self.post_wx_layout_request() - return - - # If this container owns its layout, update the manager unless - # a relayout is pending. A pending relayout means the manager - # has already been reset and the layout indices are invalid. - manager = self._layout_manager - if manager is not None: - if self._layout_timer is None: - with self.geometry_guard(): - manager.update_geometry(item.layout_index) - self._update_size_bounds() - self._update_geometries() - return - - # If an ancestor container owns the layout, proxy the call. - if container is not None: - container.geometry_updated(item) - - @contextmanager - def geometry_guard(self): - """ A context manager for guarding the geometry of the widget. - - This is a reimplementation of the superclass method which uses - the internally computed min and max size of the container. - - """ - old_hint = self.widget.GetBestSize() - old_min = self.min_size - old_max = self.max_size - yield - if (old_hint != self.widget.GetBestSize() or - old_min != self.min_size or - old_max != self.max_size): - self.geometry_updated() - - @staticmethod - def margins_func(widget_item): - """ Get the margins for the given widget item. - - The container margins are added to the user provided padding - to determine the final offset from a layout box boundary to - the corresponding content line. The default container margins - are zero. This method can be reimplemented by subclasses to - supply different margins. - - Returns - ------- - result : tuple - A 4-tuple of margins (top, right, bottom, left). - - """ - return (0, 0, 0, 0) - - def margins_updated(self, item=None): - """ Notify the layout system that the margins have changed. - - Parameters - ---------- - item : WxContainer, optional - The container widget with the updated margins. If this is - None, it indicates that this container's margins are the - ones which have changed. - - """ - # If this container owns its layout, update the manager unless - # a relayout is pending. A pending relayout means the manager - # has already been reset and the layout indices are invalid. - manager = self._layout_manager - if manager is not None: - if self._layout_timer is None: - index = item.layout_index if item else -1 - with self.geometry_guard(): - manager.update_margins(index) - self._update_size_bounds() - self._update_geometries() - return - - # If an ancestor container owns the layout, forward the call. - container = self.layout_container - if container is not None: - container.margins_updated(item or self) - - #-------------------------------------------------------------------------- - # Private Event Handlers - #-------------------------------------------------------------------------- - def _on_resized(self, event): - """ The event handler for the EVT_SIZE event. - - This triggers a geometry update for the decendant children. - - """ - if self._is_shown: - self._update_geometries() - - def _on_shown(self, event): - """ The event handler for the EVT_SHOW event. - - This handler toggles the value of the _is_shown flag. - - """ - # The EVT_SHOW event is not reliable. For example, it is not - # emitted on the children of widgets that were hidden. So, if - # this container is the child of, say, a notebook page, then - # the switching of tabs does not emit a show event. So, the - # notebook page must cooperatively emit a show event on this - # container. Therefore, we can't treat this event as a 'real' - # toolkit event, we just use it as a hint. - self._is_shown = shown = event.GetShow() - if shown: - self._update_geometries() - - def _on_relayout_timer(self): - """ Rebuild the layout for the container. - - This method is invoked when the relayout timer is triggered. It - will reset the manager and update the geometries of the children. - - """ - self._layout_timer.Stop() - del self._layout_timer - with self.geometry_guard(): - self._setup_manager() - self._update_size_bounds() - self._update_geometries() - self.widget.Thaw() - - #-------------------------------------------------------------------------- - # Private Layout Handling - #-------------------------------------------------------------------------- - def _setup_manager(self): - """ Setup the layout manager. - - This method will create or reset the layout manager and update - it with a new layout table. - - """ - # Layout ownership can only be transferred *after* the init - # layout method is called, as layout occurs bottom up. The - # manager is only created if ownership is unlikely to change. - share_layout = self.declaration.share_layout - if share_layout and isinstance(self.parent(), WxContainer): - timer = self._layout_timer - if timer is not None: - timer.Stop() - del self._layout_timer - del self._layout_manager - return - - manager = self._layout_manager - if manager is None: - item = WxContainerItem() - item.declaration = self.declaration - item.widget = self.widget - item.origin = LayoutPoint() - item.offset = LayoutPoint() - item.margins_func = self.margins_func - manager = self._layout_manager = LayoutManager(item) - manager.set_items(self._create_layout_items()) - - def _update_geometries(self): - """ Update the geometries of the layout children. - - This method will resize the layout manager to the container size. - - """ - manager = self._layout_manager - if manager is not None: - width, height = self.widget.GetSizeTuple() - manager.resize(width, height) - - def _update_size_bounds(self): - """ Update the size bounds of the underlying container. - - This method will update the min, max, and best size of the - container. It will not automatically trigger a geometry - notification. - - """ - widget = self.widget - manager = self._layout_manager - if manager is None: - best_size = DEFAULT_BEST_SIZE - min_size = DEFAULT_MIN_SIZE - max_size = DEFAULT_MAX_SIZE - else: - best_size = wx.Size(*manager.best_size()) - min_size = wx.Size(*manager.min_size()) - max_size = wx.Size(*manager.max_size()) - - # Store the computed min and max size, which is used by the - # WxChildContainerItem to provide min and max size constraints. - self.min_size = min_size - self.max_size = max_size - - # If this is a child container, min and max size are not applied - # to the widget since the ancestor manager must be the ultimate - # authority on layout size. - widget.SetBestSize(best_size) - if isinstance(self.parent(), WxContainer): - widget.SetMinSize(DEFAULT_MIN_SIZE) - widget.SetMaxSize(DEFAULT_MAX_SIZE) - else: - widget.SetMinSize(min_size) - widget.SetMaxSize(max_size) - - def _create_layout_items(self): - """ Create a layout items for the container decendants. - - The layout items are created by traversing the decendants in - breadth-first order and setting up a LayoutItem object for - each decendant. The layout item is populated with an offset - point which represents the offset of the widgets parent to - the origin of the widget which owns the layout solver. This - point is substracted from the solved origin of the widget. - - Returns - ------- - result : list - A list of LayoutItem objects which represent the flat - layout traversal. - - """ - layout_items = [] - offset = LayoutPoint() - queue = deque((offset, child) for child in self.children()) - while queue: - offset, child = queue.popleft() - if isinstance(child, WxConstraintsWidget): - child.layout_container = self - origin = LayoutPoint() - if isinstance(child, WxContainer): - if child.declaration.share_layout: - item = WxSharedContainerItem() - item.margins_func = child.margins_func - for subchild in child.children(): - queue.append((origin, subchild)) - else: - item = WxChildContainerItem() - else: - item = WxLayoutItem() - item.declaration = child.declaration - item.widget = child.widget - item.offset = offset - item.origin = origin - child.layout_index = len(layout_items) - layout_items.append(item) - return layout_items diff --git a/enaml/wx/wx_control.py b/enaml/wx/wx_control.py deleted file mode 100644 index 92adbfa68..000000000 --- a/enaml/wx/wx_control.py +++ /dev/null @@ -1,18 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -from enaml.widgets.control import ProxyControl - -from .wx_constraints_widget import WxConstraintsWidget - - -class WxControl(WxConstraintsWidget, ProxyControl): - """ A Wx implementation of an Enaml Control. - - """ - # The WxConstraintsWidget superclass is a sufficient implementation. - pass diff --git a/enaml/wx/wx_date_selector.py b/enaml/wx/wx_date_selector.py deleted file mode 100644 index 4a11eac39..000000000 --- a/enaml/wx/wx_date_selector.py +++ /dev/null @@ -1,117 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.date_selector import ProxyDateSelector - -from .wx_bounded_date import ( - WxBoundedDate, CHANGED_GUARD, as_wx_date, as_py_date -) - - -class WxDateSelector(WxBoundedDate, ProxyDateSelector): - """ A Wx implementation of an Enaml ProxyDateSelector. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wx.DatePickerCtrl) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the wx.DatePickerCtrl widget. - - """ - self.widget = wx.DatePickerCtrl(self.parent_widget()) - - def init_widget(self): - """ Initialize the widget. - - """ - super(WxDateSelector, self).init_widget() - d = self.declaration - self.set_date_format(d.date_format) - self.set_calendar_popup(d.calendar_popup) - self.widget.Bind(wx.EVT_DATE_CHANGED, self.on_date_changed) - - #-------------------------------------------------------------------------- - # Abstract API Implementation - #-------------------------------------------------------------------------- - def get_date(self): - """ Return the current date in the control. - - Returns - ------- - result : date - The current control date as a date object. - - """ - return as_py_date(self.widget.GetValue()) - - def set_minimum(self, date): - """ Set the widget's minimum date. - - Parameters - ---------- - date : date - The date object to use for setting the minimum date. - - """ - widget = self.widget - widget.SetRange(as_wx_date(date), widget.GetUpperLimit()) - - - def set_maximum(self, date): - """ Set the widget's maximum date. - - Parameters - ---------- - date : date - The date object to use for setting the maximum date. - - """ - widget = self.widget - widget.SetRange(widget.GetLowerLimit(), as_wx_date(date)) - - def set_date(self, date): - """ Set the widget's current date. - - Parameters - ---------- - date : date - The date object to use for setting the date. - - """ - self._guard |= CHANGED_GUARD - try: - self.widget.SetValue(as_wx_date(date)) - finally: - self._guard &= ~CHANGED_GUARD - - def set_date_format(self, format): - """ Set the widget's date format. - - Parameters - ---------- - format : string - A Python time formatting string. - - .. note:: Changing the format on wx is not supported. - See http://trac.wxwidgets.org/ticket/10988 - - """ - pass - - def set_calendar_popup(self, popup): - """ This is not supported on Wx. - - """ - pass diff --git a/enaml/wx/wx_deferred_caller.py b/enaml/wx/wx_deferred_caller.py deleted file mode 100644 index de9e41051..000000000 --- a/enaml/wx/wx_deferred_caller.py +++ /dev/null @@ -1,85 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - - -class wxDeferredCaller(object): - """ A simple object which facilitates running callbacks on the main - application thread. - - """ - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def DeferredCall(self, callback, *args, **kwargs): - """ Execute the callback on the main gui thread. - - Parameters - ---------- - callback : callable - The callable object to execute on the main thread. - - *args, **kwargs - Any additional positional and keyword arguments to pass to - the callback. - - """ - wx.CallAfter(callback, *args, **kwargs) - - def TimedCall(self, ms, callback, *args, **kwargs): - """ Execute a callback on timer in the main gui thread. - - Parameters - ---------- - ms : int - The time to delay, in milliseconds, before executing the - callable. - - callback : callable - The callable object to execute at on the timer. - - *args, **kwargs - Any additional positional and keyword arguments to pass to - the callback. - - """ - f = lambda: wx.CallLater(ms, callback, *args, **kwargs) - wx.CallAfter(f) - - -#: A globally available caller instance. This will be created on demand -#: by the globally available caller functions. -_caller = None - - -def DeferredCall(callback, *args, **kwargs): - """ Execute the callback on the main gui thread. - - This is a convenience wrapper around QDeferredCaller.deferredCall. - This should only be called after the QApplication is created. - - """ - global _caller - c = _caller - if c is None: - c = _caller = wxDeferredCaller() - c.DeferredCall(callback, *args, **kwargs) - - -def TimedCall(ms, callback, *args, **kwargs): - """ Execute a callback on a timer in the main gui thread. - - This is a convenience wrapper around QDeferredCaller.timedCall. - This should only be called after the QApplication is created. - - """ - global _caller - c = _caller - if c is None: - c = _caller = wxDeferredCaller() - c.TimedCall(ms, callback, *args, **kwargs) diff --git a/enaml/wx/wx_dock_pane.py b/enaml/wx/wx_dock_pane.py deleted file mode 100644 index b727f404e..000000000 --- a/enaml/wx/wx_dock_pane.py +++ /dev/null @@ -1,735 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx -import wx.lib.newevent - -from atom.api import Int, Typed - -from enaml.widgets.dock_pane import ProxyDockPane - -from .wx_container import WxContainer -from .wx_single_widget_sizer import wxSingleWidgetSizer -from .wx_upstream import aui -from .wx_widget import WxWidget - - -#: A mapping from Enaml dock areas to wx aui dock area enums -_DOCK_AREA_MAP = { - 'top': aui.AUI_DOCK_TOP, - 'right': aui.AUI_DOCK_RIGHT, - 'bottom': aui.AUI_DOCK_BOTTOM, - 'left': aui.AUI_DOCK_LEFT, -} - -#: A mapping from wx aui dock area enums to Enaml dock areas. -_DOCK_AREA_INV_MAP = { - aui.AUI_DOCK_TOP: 'top', - aui.AUI_DOCK_RIGHT: 'right', - aui.AUI_DOCK_BOTTOM: 'bottom', - aui.AUI_DOCK_LEFT: 'left', -} - -#: A mapping from Enaml allowed dock areas to wx direction enums. -_ALLOWED_AREAS_MAP = { - 'top': wx.TOP, - 'right': wx.RIGHT, - 'bottom': wx.BOTTOM, - 'left': wx.LEFT, - 'all': wx.ALL, -} - -#: A mappint from Enaml orientations to wx orientations. -_ORIENTATION_MAP = { - 'horizontal': wx.HORIZONTAL, - 'vertical': wx.VERTICAL, -} - - -#: An event emitted when the dock pane is floated. -wxDockPaneFloatedEvent, EVT_DOCK_PANE_FLOATED = wx.lib.newevent.NewEvent() - -#: An event emitted when the dock is docked. -wxDockPaneDockedEvent, EVT_DOCK_PANE_DOCKED = wx.lib.newevent.NewEvent() - -#: An event emitted when the dock pane is closed. -wxDockPaneClosedEvent, EVT_DOCK_PANE_CLOSED = wx.lib.newevent.NewEvent() - - -class wxDockPane(wx.Panel): - """ A wxPanel subclass which adds DockPane features. - - """ - def __init__(self, parent, *args, **kwargs): - """ Initialize a wxDockPane. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments needed to initialize - a wxPanel. - - """ - super(wxDockPane, self).__init__(parent, *args, **kwargs) - self._is_open = True - self._title = u'' - self._title_bar_visible = True - self._title_bar_orientation = wx.HORIZONTAL - self._closable = True - self._movable = True - self._floatable = True - self._floating = False - self._dock_area = aui.AUI_DOCK_LEFT - self._allowed_dock_areas = wx.ALL - self._dock_widget = None - self.SetSizer(wxSingleWidgetSizer()) - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def _FindPaneManager(self): - """ Find the pane manager for this dock pane. - - Returns - ------- - result : AuiManager or None - The AuiManager for this dock pane, or None if not found. - - """ - event = aui.AuiManagerEvent(aui.wxEVT_AUI_FIND_MANAGER) - self.ProcessEvent(event) - return event.GetManager() - - def _PaneInfoOperation(self, closure): - """ A private method which will run the given closure if there - is a valid pane info object for this dock pane. - - """ - manager = self._FindPaneManager() - if manager is not None: - pane = manager.GetPane(self) - if pane.IsOk(): - closure(pane) - manager.Update() - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def OnClose(self, event): - """ Handles the parent EVT_AUI_PANE_CLOSE event. - - This event handler is called directly by the parent wxMainWindow - from its pane close event handler. This handler simply emits the - EVT_DOCK_PANE_CLOSED event. - - """ - self._is_open = False - wx.PostEvent(self, wxDockPaneClosedEvent()) - - def OnFloated(self, event): - """ Handles the parent EVT_AUI_PANE_FLOATED event. - - This event handler is called directly by the parent wxMainWindow - from its pane floated event handler. This handler simply emits - the EVT_DOCK_PANE_FLOATED event. - - """ - self._floating = True - wx.PostEvent(self, wxDockPaneFloatedEvent()) - - def OnDocked(self, event): - """ Handles the parent EVT_AUI_PANE_DOCKED event. - - This event handler is called directly by the parent wxMainWindow - from its pane docked event handler. This handler simply emits - the EVT_DOCK_PANE_DOCKED event. - - """ - self._floating = False - self._dock_area = event.GetPane().dock_direction - wx.PostEvent(self, wxDockPaneDockedEvent()) - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def MakePaneInfo(self): - """ Create a new AuiPaneInfo object for this dock pane. - - This is called by the wxMainWindow when it adds this dock pane - to its internal layout for the first time. - - Returns - ------- - result : AuiPaneInfo - An initialized AuiPaneInfo object for this pane. - - """ - info = aui.AuiPaneInfo() - - # Don't allow docking panes as a notebook since that causes - # issues with finding the proper parent manager on updates - # and it makes resizing of dock panes abysmally slow. - info.NotebookDockable(False) - - info.BestSize(self.GetBestSize()) - info.MinSize(self.GetEffectiveMinSize()) - info.Show(self.IsOpen()) - info.Caption(self.GetTitle()) - info.CloseButton(self.GetClosable()) - info.Movable(self.GetMovable()) - info.Floatable(self.GetFloatable()) - info.Direction(self.GetDockArea()) - - left = self.GetTitleBarOrientation() == wx.VERTICAL - info.CaptionVisible(self.GetTitleBarVisible(), left) - - areas = self.GetAllowedDockAreas() - info.TopDockable(bool(areas & wx.TOP)) - info.RightDockable(bool(areas & wx.RIGHT)) - info.LeftDockable(bool(areas & wx.LEFT)) - info.BottomDockable(bool(areas & wx.BOTTOM)) - - if self.GetFloating(): - info.Float() - else: - info.Dock() - - return info - - def GetDockWidget(self): - """ Get the dock widget being managed by this pane. - - Returns - ------- - result : wxWindow or None - The wx widget being managed by this dock pane, or None - if no widget is being managed. - - """ - return self._dock_widget - - def SetDockWidget(self, widget): - """ Set the dock widget to be managed by the pane. - - Any old dock widget will be removed, but not destroyed. - - Parameters - ---------- - widget : wxWindow - The wx widget to use as the dock widget for this pane. - - """ - old_widget = self._dock_widget - if old_widget: - old_widget.Hide() - self._dock_widget = widget - self.GetSizer().Add(widget) - self.UpdateSizing() - - def UpdateSizing(self): - """ Trigger a sizing update of the pane manager. - - """ - def closure(pane): - pane.MinSize(self.GetBestSize()) - self._PaneInfoOperation(closure) - - def IsOpen(self): - """ Get whether or not the dock pane is open. - - Returns - ------- - result : bool - True if the pane is open, False otherwise. - - """ - return self._is_open - - def Open(self): - """ Open the dock pane in the main window. - - If the pane is already open, this method is a no-op. - - """ - self._is_open = True - def closure(pane): - if not pane.IsShown(): - pane.Show(True) - self._PaneInfoOperation(closure) - - def Close(self): - """ Close the dock pane in the main window. - - If the pane is already closed, this method is no-op. - - """ - self._is_open = False - def closure(pane): - if pane.IsShown(): - pane.Show(False) - self._PaneInfoOperation(closure) - - def GetTitle(self): - """ Get the title for the dock pane. - - Returns - ------- - result : unicode - The title of the dock pane. - - """ - return self._title - - def SetTitle(self, title): - """ Set the title for the dock pane. - - Parameters - ---------- - title : unicode - The title to use for the dock pane. - - """ - if self._title != title: - self._title = title - def closure(pane): - pane.Caption(title) - self._PaneInfoOperation(closure) - - def GetTitleBarVisible(self): - """ Get the title bar visibility state for the dock pane. - - Returns - ------- - result : bool - Whether or not the title bar is visible. - - """ - return self._title_bar_visible - - def SetTitleBarVisible(self, visible): - """ Set the title bar visibility state for the dock pane. - - Parameters - ---------- - visible : bool - Whether or not the title bar should be visible. - - """ - if self._title_bar_visible != visible: - self._title_bar_visible = visible - def closure(pane): - left = self._title_bar_orientation == wx.VERTICAL - pane.CaptionVisible(visible, left) - self._PaneInfoOperation(closure) - - def GetTitleBarOrientation(self): - """ Get the title bar orientation for the dock pane. - - Returns - ------- - result : int - The orientation of the title bar. Either wx.HORIZONTAL - or wx.VERTICAL - - """ - return self._title_bar_orientation - - def SetTitleBarOrientation(self, orientation): - """ Set the title bar orientation for the dock pane. - - Parameters - ---------- - result : int - The orientation of the title bar. Either wx.HORIZONTAL - or wx.VERTICAL - - """ - if self._title_bar_orientation != orientation: - self._title_bar_orientation = orientation - def closure(pane): - visible = self._title_bar_visible - left = orientation == wx.VERTICAL - pane.CaptionVisible(visible, left) - self._PaneInfoOperation(closure) - - def GetClosable(self): - """ Get the closable state of the pane. - - Returns - ------- - result : bool - Whether or not the pane is closable. - - """ - return self._closable - - def SetClosable(self, closable): - """ Set the closable state of the pane. - - Parameters - ---------- - closable : bool - Whether or not the pane is closable. - - """ - if self._closable != closable: - self._closable = closable - def closure(pane): - pane.CloseButton(closable) - self._PaneInfoOperation(closure) - - def GetMovable(self): - """ Get the movable state of the pane. - - Returns - ------- - result : bool - Whether or not the pane is movable. - - """ - return self._movable - - def SetMovable(self, movable): - """ Set the movable state of the pane. - - Parameters - ---------- - movable : bool - Whether or not the pane is movable. - - """ - if self._movable != movable: - self._movable = movable - def closure(pane): - pane.Movable(movable) - self._PaneInfoOperation(closure) - - def GetFloatable(self): - """ Get the floatable state of the pane. - - Returns - ------- - result : bool - Whether or not the pane is floatable. - - """ - return self._floatable - - def SetFloatable(self, floatable): - """ Set the floatable state of the pane. - - Parameters - ---------- - floatable : bool - Whether or not the pane is floatable. - - """ - if self._floatable != floatable: - self._floatable = floatable - def closure(pane): - pane.Floatable(floatable) - self._PaneInfoOperation(closure) - - def GetFloating(self): - """ Get the floating state of the pane. - - Returns - ------- - result : bool - Whether or not the pane is floating. - - """ - return self._floating - - def SetFloating(self, floating): - """ Set the floating state of the pane. - - Parameters - ---------- - floating : bool - Whether or not the pane should be floating. - - """ - if self._floating != floating: - self._floating = floating - def closure(pane): - if floating: - pane.Float() - else: - pane.Dock() - self._PaneInfoOperation(closure) - - def GetDockArea(self): - """ Get the current dock area of the pane. - - Returns - ------- - result : int - The current dock area of the pane. One of the wx enums - LEFT, RIGHT, TOP, or BOTTOM. - - """ - return self._dock_area - - def SetDockArea(self, dock_area): - """ Set the dock area for the pane. - - Parameters - ---------- - dock_area : int - The dock area for the pane. One of the wx enums LEFT, - RIGHT, TOP, or BOTTOM. - - """ - if self._dock_area != dock_area: - self._dock_area = dock_area - def closure(pane): - pane.Direction(dock_area) - self._PaneInfoOperation(closure) - - def GetAllowedDockAreas(self): - """ Get the allowed dock areas for the pane. - - Returns - ------- - result : int - The allowed dock areas for the pane. One of the wx enums - LEFT, RIGHT, TOP, BOTTOM, or ALL. - - """ - return self._allowed_dock_areas - - def SetAllowedDockAreas(self, dock_areas): - """ Set the allowed dock areas for the pane. - - Parameters - ---------- - dock_areas : int - The allowed dock areas for the pane. One of the wx enums - LEFT, RIGHT, TOP, BOTTOM, or ALL. - - """ - if self._allowed_dock_areas != dock_areas: - self._allowed_dock_areas = dock_areas - def closure(pane): - pane.TopDockable(bool(dock_areas & wx.TOP)) - pane.RightDockable(bool(dock_areas & wx.RIGHT)) - pane.LeftDockable(bool(dock_areas & wx.LEFT)) - pane.BottomDockable(bool(dock_areas & wx.BOTTOM)) - self._PaneInfoOperation(closure) - - -# cyclic notification guard flags -FLOATED_GUARD = 0x1 - - -class WxDockPane(WxWidget, ProxyDockPane): - """ A Wx implementation of an Enaml ProxyDockPane. - - """ - #: A reference tot he widget created by the proxy. - widget = Typed(wxDockPane) - - #: Cyclic notification guard. This a bitfield of multiple guards. - _guard = Int(0) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the wxDockPane widget. - - """ - self.widget = wxDockPane(self.parent_widget()) - - def init_widget(self): - """ Initialize the dock pane control. - - """ - super(WxDockPane, self).init_widget() - d = self.declaration - self.set_title(d.title) - self.set_title_bar_visible(d.title_bar_visible) - self.set_title_bar_orientation(d.title_bar_orientation) - self.set_closable(d.closable) - self.set_movable(d.movable) - self.set_floatable(d.floatable) - self.set_floating(d.floating) - self.set_dock_area(d.dock_area) - self.set_allowed_dock_areas(d.allowed_dock_areas) - widget = self.widget - widget.Bind(EVT_DOCK_PANE_FLOATED, self.on_floated) - widget.Bind(EVT_DOCK_PANE_DOCKED, self.on_docked) - widget.Bind(EVT_DOCK_PANE_CLOSED, self.on_closed) - - def init_layout(self): - """ Handle the layout initialization for the dock pane. - - """ - super(WxDockPane, self).init_layout() - self.widget.SetDockWidget(self.dock_widget()) - - #-------------------------------------------------------------------------- - # Utility Methods - #-------------------------------------------------------------------------- - def dock_widget(self): - """ Find and return the dock widget child for this widget. - - Returns - ------- - result : wxWindow or None - The dock widget defined for this widget, or None if one is - not defined. - - """ - d = self.declaration.dock_widget() - if d is not None: - return d.proxy.widget - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def child_added(self, child): - """ Handle the child added event for a WxDockPane. - - """ - super(WxDockPane, self).child_added(child) - if isinstance(child, WxContainer): - self.widget.SetDockWidget(self.dock_widget()) - - def child_removed(self, child): - """ Handle the child removed event for a WxDockPane. - - """ - super(WxDockPane, self).child_removed(child) - if isinstance(child, WxContainer): - self.widget.SetDockWidget(self.dock_widget()) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_closed(self, event): - """ The event handler for the EVT_DOCK_PANE_CLOSED event. - - """ - # The closed signal is only emitted when the widget is closed - # by the user, so there is no need for a loopback guard. - self.declaration.visible = False - self.declaration.closed() - - def on_floated(self, event): - """ The event handler for the EVT_DOCK_PANE_FLOATED event. - - """ - if not self._guard & FLOATED_GUARD: - self._guard |= FLOATED_GUARD - try: - self.declaration.floating = True - finally: - self._guard &= ~FLOATED_GUARD - - def on_docked(self, event): - """ The event handler for the EVT_DOCK_PANE_AREA event. - - """ - area = self.widget.GetDockArea() - if not self._guard & FLOATED_GUARD: - self._guard |= FLOATED_GUARD - try: - self.declaration.floating = False - self.declaration.dock_area = _DOCK_AREA_INV_MAP[area] - finally: - self._guard &= ~FLOATED_GUARD - - #-------------------------------------------------------------------------- - # ProxyDockPane API - #-------------------------------------------------------------------------- - def set_visible(self, visible): - """ An overridden visibility setter which to opens|closes the - dock pane. - - """ - if visible: - self.widget.Open() - else: - self.widget.Close() - - def ensure_visible(self): - """ An overridden visibility setter which to opens|closes the - dock pane. - - """ - self.set_visible(True) - - def ensure_hidden(self): - """ An overridden visibility setter which to opens|closes the - dock pane. - - """ - self.set_visible(False) - - def set_title(self, title): - """ Set the title on the underlying widget. - - """ - self.widget.SetTitle(title) - - def set_title_bar_visible(self, visible): - """ Set the title bar visibility of the underlying widget. - - """ - self.widget.SetTitleBarVisible(visible) - - def set_title_bar_orientation(self, orientation): - """ Set the title bar orientation of the underyling widget. - - """ - self.widget.SetTitleBarOrientation(_ORIENTATION_MAP[orientation]) - - def set_closable(self, closable): - """ Set the closable state on the underlying widget. - - """ - self.widget.SetClosable(closable) - - def set_movable(self, movable): - """ Set the movable state on the underlying widget. - - """ - self.widget.SetMovable(movable) - - def set_floatable(self, floatable): - """ Set the floatable state on the underlying widget. - - """ - self.widget.SetFloatable(floatable) - - def set_floating(self, floating): - """ Set the floating staet on the underlying widget. - - """ - if not self._guard & FLOATED_GUARD: - self._guard |= FLOATED_GUARD - try: - self.widget.SetFloating(floating) - finally: - self._guard &= ~FLOATED_GUARD - - def set_dock_area(self, dock_area): - """ Set the dock area on the underyling widget. - - """ - self.widget.SetDockArea(_DOCK_AREA_MAP[dock_area]) - - def set_allowed_dock_areas(self, dock_areas): - """ Set the allowed dock areas on the underlying widget. - - """ - wx_areas = 0 - for area in dock_areas: - wx_areas |= _ALLOWED_AREAS_MAP[area] - self.widget.SetAllowedDockAreas(wx_areas) diff --git a/enaml/wx/wx_factories.py b/enaml/wx/wx_factories.py deleted file mode 100644 index ec31bb278..000000000 --- a/enaml/wx/wx_factories.py +++ /dev/null @@ -1,187 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -def action_factory(): - from .wx_action import WxAction - return WxAction - - -def action_group_factory(): - from .wx_action_group import WxActionGroup - return WxActionGroup - - -def calendar_factory(): - from .wx_calendar import WxCalendar - return WxCalendar - - -def check_box_factory(): - from .wx_check_box import WxCheckBox - return WxCheckBox - - -def combo_box_factory(): - from .wx_combo_box import WxComboBox - return WxComboBox - - -def container_factory(): - from .wx_container import WxContainer - return WxContainer - - -def date_selector_factory(): - from .wx_date_selector import WxDateSelector - return WxDateSelector - - -# def datetime_selector_factory(): -# from .wx_datetime_selector import WxDatetimeSelector -# return WxDatetimeSelector - - -def dock_pane_factory(): - from .wx_dock_pane import WxDockPane - return WxDockPane - - -def field_factory(): - from .wx_field import WxField - return WxField - - -def group_box_factory(): - from .wx_group_box import WxGroupBox - return WxGroupBox - - -def html_factory(): - from .wx_html import WxHtml - return WxHtml - - -# def image_view_factory(): -# from .wx_image_view import WxImageView -# return WxImageView - - -def label_factory(): - from .wx_label import WxLabel - return WxLabel - - -def main_window_factory(): - from .wx_main_window import WxMainWindow - return WxMainWindow - - -def menu_factory(): - from .wx_menu import WxMenu - return WxMenu - - -def menu_bar_factory(): - from .wx_menu_bar import WxMenuBar - return WxMenuBar - - -def mpl_canvas_factory(): - from .wx_mpl_canvas import WxMPLCanvas - return WxMPLCanvas - - -def notebook_factory(): - from .wx_notebook import WxNotebook - return WxNotebook - - -def page_factory(): - from .wx_page import WxPage - return WxPage - - -def push_button_factory(): - from .wx_push_button import WxPushButton - return WxPushButton - - -def progress_bar_factory(): - from .wx_progress_bar import WxProgressBar - return WxProgressBar - - -def radio_button_factory(): - from .wx_radio_button import WxRadioButton - return WxRadioButton - - -def scroll_area_factory(): - from .wx_scroll_area import WxScrollArea - return WxScrollArea - - -def slider_factory(): - from .wx_slider import WxSlider - return WxSlider - - -def spin_box_factory(): - from .wx_spin_box import WxSpinBox - return WxSpinBox - - -def split_item_factory(): - from .wx_split_item import WxSplitItem - return WxSplitItem - - -def splitter_factory(): - from .wx_splitter import WxSplitter - return WxSplitter - - -def tool_bar_factory(): - from .wx_tool_bar import WxToolBar - return WxToolBar - - -def window_factory(): - from .wx_window import WxWindow - return WxWindow - - -WX_FACTORIES = { - 'Action': action_factory, - 'ActionGroup': action_group_factory, - 'Calendar': calendar_factory, - 'CheckBox': check_box_factory, - 'ComboBox': combo_box_factory, - 'Container': container_factory, - 'DateSelector': date_selector_factory, - 'DockPane': dock_pane_factory, - 'Field': field_factory, - 'GroupBox': group_box_factory, - 'Html': html_factory, - 'Label': label_factory, - 'MainWindow': main_window_factory, - 'Menu': menu_factory, - 'MenuBar': menu_bar_factory, - 'MPLCanvas': mpl_canvas_factory, - 'Notebook': notebook_factory, - 'Page': page_factory, - 'PushButton': push_button_factory, - 'ProgressBar': progress_bar_factory, - 'RadioButton': radio_button_factory, - 'ScrollArea': scroll_area_factory, - 'Slider': slider_factory, - 'SpinBox': spin_box_factory, - 'SplitItem': split_item_factory, - 'Splitter': splitter_factory, - 'ToolBar': tool_bar_factory, - 'Window': window_factory, -} diff --git a/enaml/wx/wx_field.py b/enaml/wx/wx_field.py deleted file mode 100644 index d0e0819fe..000000000 --- a/enaml/wx/wx_field.py +++ /dev/null @@ -1,337 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Int, Typed - -from enaml.widgets.field import ProxyField - -from .wx_control import WxControl - - -class wxLineEdit(wx.TextCtrl): - """ A wx.TextCtrl subclass which is similar to a QLineEdit in terms - of features and behavior. - - """ - def __init__(self, *args, **kwargs): - """ Initialize a wxLineEdit. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments to initialize a - wx.TextCtrl. - - """ - super(wxLineEdit, self).__init__(*args, **kwargs) - self._placeholder_text = '' - self._placeholder_active = False - self._user_fgcolor = None - self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) - self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def _UpdatePlaceholderDisplay(self): - """ Updates the display with the placeholder text if no text - is currently set for the control. - - """ - if not self.GetValue() and self._placeholder_text: - self.ChangeValue(self._placeholder_text) - color = wx.Color(95, 95, 95) - super(wxLineEdit, self).SetForegroundColour(color) - self._placeholder_active = True - - def _RemovePlaceholderDisplay(self): - """ Removes the placeholder text if it is currently active. - - """ - if self._placeholder_active: - self.ChangeValue('') - color = self._user_fgcolor or wx.Color(0, 0, 0) - super(wxLineEdit, self).SetForegroundColour(color) - self._placeholder_active = False - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def OnKillFocus(self, event): - """ Refreshes the placeholder display when the control loses - focus. - - """ - self._UpdatePlaceholderDisplay() - event.Skip() - - def OnSetFocus(self, event): - """ Removes the placeholder display when the control receives - focus. - - """ - self._RemovePlaceholderDisplay() - event.Skip() - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def GetBestSize(self): - """ Overridden best size method to add 44 pixels in width to the - field. This makes Wx consistent with Qt. - - """ - size = super(wxLineEdit, self).GetBestSize() - return wx.Size(size.GetWidth() + 44, size.GetHeight()) - - def SetPlaceHolderText(self, placeholder_text): - """ Sets the placeholder text to the given value. Pass an empty - string to turn off the placeholder text functionality. - - """ - self._placeholder_text = placeholder_text - self._UpdatePlaceholderDisplay() - - def GetPlaceHolderText(self): - """ Returns the placeholder text for this control. - - """ - return self._placeholder_text - - def ChangeValue(self, text): - """ Overridden method which moves the insertion point to the end - of the field when changing the text value. This causes the field - to behave like Qt. - - """ - super(wxLineEdit, self).ChangeValue(text) - self.SetInsertionPoint(len(text)) - - def GetValue(self): - """ Returns string value in the control, or an empty string if - the placeholder text is active. - - """ - if self._placeholder_active: - return '' - return super(wxLineEdit, self).GetValue() - - def SetForegroundColour(self, wxColor, force=False): - """ Sets the foreground color of the field. If the placeholder - text is being shown, `force` must be True in order to override - the placeholder text color. - - """ - self._user_fgcolor = wxColor - if self._placeholder_active and not force: - return - super(wxLineEdit, self).SetForegroundColour(wxColor) - - -# Guard flags -TEXT_GUARD = 0x1 -ERROR_FLAG = 0x2 - - -class WxField(WxControl, ProxyField): - """ A Wx implementation of an Enaml ProxyField. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxLineEdit) - - #: A collapsing timer for auto sync text. - _text_timer = Typed(wx.Timer) - - #: Cyclic notification guard. This a bitfield of multiple guards. - _guard = Int(0) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Creates the underlying wxLineEdit widget. - - """ - # We have to do a bit of initialization in the create method - # since wx requires the style of certain things to be set at - # the point of instantiation - d = self.declaration - style = wx.TE_PROCESS_ENTER - if d.read_only: - style |= wx.TE_READONLY - else: - style &= ~wx.TE_READONLY - if d.echo_mode == 'normal': - style &= ~wx.TE_PASSWORD - else: - style |= wx.TE_PASSWORD - self.widget = wxLineEdit(self.parent_widget(), style=style) - - def init_widget(self): - """ Create and initialize the underlying widget. - - """ - super(WxField, self).init_widget() - d = self.declaration - if d.text: - self.set_text(d.text) - if d.mask: - self.set_mask(d.mask) - if d.placeholder: - self.set_placeholder(d.placeholder) - self.set_echo_mode(d.echo_mode) - self.set_max_length(d.max_length) - self.set_read_only(d.read_only) - self.set_submit_triggers(d.submit_triggers) - self.widget.Bind(wx.EVT_TEXT, self.on_text_edited) - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def _validate_and_apply(self): - """ Validate and apply the text in the control. - - """ - d = self.declaration - text = self.widget.GetValue() - if d.validator and not d.validator.validate(text): - text = d.validator.fixup(text) - if not d.validator.validate(text): - return - self._clear_error_state() - d.text = text - - def _set_error_state(self): - """ Set the error state of the widget. - - """ - # A temporary hack until styles are implemented - if not self._guard & ERROR_FLAG: - self._guard |= ERROR_FLAG - # XXX attempting to change the field style here is futile - - def _clear_error_state(self): - """ Clear the error state of the widget. - - """ - # A temporary hack until styles are implemented - if self._guard & ERROR_FLAG: - self._guard &= ~ERROR_FLAG - # XXX attempting to change the field style here is futile - - #-------------------------------------------------------------------------- - # Event Handling - #-------------------------------------------------------------------------- - def on_submit_text(self, event): - """ The event handler for the text submit triggers. - - """ - # Only skip the focus event: wx triggers the system beep if the - # enter event is skipped. - if isinstance(event, wx.FocusEvent): - event.Skip() - self._guard |= TEXT_GUARD - try: - self._validate_and_apply() - finally: - self._guard &= ~TEXT_GUARD - - def on_text_edited(self, event): - """ The event handler for the text edited event. - - """ - # Temporary kludge until error style is fully implemented - d = self.declaration - if d.validator and not d.validator.validate(self.widget.GetValue()): - self._set_error_state() - self.widget.SetToolTip(wx.ToolTip(d.validator.message)) - else: - self._clear_error_state() - self.widget.SetToolTip(wx.ToolTip('')) - if self._text_timer is not None: - self._text_timer.Start(300, oneShot=True) - - #-------------------------------------------------------------------------- - # ProxyField API - #-------------------------------------------------------------------------- - def set_text(self, text): - """ Updates the text control with the given unicode text. - - """ - if not self._guard & TEXT_GUARD: - self.widget.ChangeValue(text) - self._clear_error_state() - - def set_mask(self, mask): - """ Set the make for the widget. - - This is not supported in Wx. - - """ - pass - - def set_submit_triggers(self, triggers): - """ Set the submit triggers for the widget. - - """ - widget = self.widget - handler = self.on_submit_text - widget.Unbind(wx.EVT_KILL_FOCUS, handler=handler) - widget.Unbind(wx.EVT_TEXT_ENTER, handler=handler) - if 'lost_focus' in triggers: - widget.Bind(wx.EVT_KILL_FOCUS, handler) - if 'return_pressed' in triggers: - widget.Bind(wx.EVT_TEXT_ENTER, handler) - if 'auto_sync' in triggers: - if self._text_timer is None: - timer = self._text_timer = wx.Timer() - timer.Bind(wx.EVT_TIMER, handler) - else: - if self._text_timer is not None: - self._text_timer.Stop() - self._text_timer = None - - def set_placeholder(self, placeholder): - """ Sets the placeholder text in the widget. - - """ - self.widget.SetPlaceHolderText(placeholder) - - def set_echo_mode(self, echo_mode): - """ Sets the echo mode of the wiget. - - """ - # Wx cannot change the echo mode dynamically. It requires - # creating a brand-new control, so we just ignore the change. - pass - - def set_max_length(self, max_length): - """ Set the max length of the control to max_length. If the max - length is <= 0 or > 32767 then the control will be set to hold - 32kb of text. - - """ - if (max_length <= 0) or (max_length > 32767): - max_length = 32767 - self.widget.SetMaxLength(max_length) - - def set_read_only(self, read_only): - """ Sets the read only state of the widget. - - """ - # Wx cannot change the read only state dynamically. It requires - # creating a brand-new control, so we just ignore the change. - pass - - def field_text(self): - """ Get the text stored in the widget. - - """ - return self.widget.GetValue() diff --git a/enaml/wx/wx_frame.py b/enaml/wx/wx_frame.py deleted file mode 100644 index e95a33e83..000000000 --- a/enaml/wx/wx_frame.py +++ /dev/null @@ -1,42 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -from atom.api import Typed - -from enaml.widgets.frame import ProxyFrame - -import wx - -from .wx_constraints_widget import WxConstraintsWidget - - -class WxFrame(WxConstraintsWidget, ProxyFrame): - """ A Wx implementation of an Enaml ProxyFrame. - - """ - #: A reference to the toolkit widget created by the proxy. - widget = Typed(wx.Panel) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Creates the QContainer widget. - - """ - self.widget = wx.Panel(self.parent_widget()) - - #-------------------------------------------------------------------------- - # ProxyFrame API - #-------------------------------------------------------------------------- - def set_border(self, border): - """ Set the border for the widget. - - This is not supported on Wx. - - """ - pass diff --git a/enaml/wx/wx_group_box.py b/enaml/wx/wx_group_box.py deleted file mode 100644 index cc12ceba9..000000000 --- a/enaml/wx/wx_group_box.py +++ /dev/null @@ -1,269 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.group_box import ProxyGroupBox - -from .wx_container import WxContainer, wxContainer - - -WX_ALIGNMENTS = { - 'left': wx.ALIGN_LEFT, - 'center': wx.ALIGN_CENTER, - 'right': wx.ALIGN_RIGHT, -} - - -class wxGroupBox(wxContainer): - """ A wxContainer sublcass that implements GroupBox functionality. - - """ - def __init__(self, *args, **kwargs): - """ Initialize a wxGroupBox. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments to initialize a - wxContainer. - - """ - super(wxGroupBox, self).__init__(*args, **kwargs) - self._title = '' - self._border = wx.StaticBox(self) - self._line = wx.StaticLine(self) - self._label = wx.StaticText(self) - self._label.Raise() - self._label_size = self._label.GetBestSize() - self._title_alignment = wx.ALIGN_LEFT - self._flat = False - # Set the panel to double buffered or suffer terrible - # rendering artifacts - self.SetDoubleBuffered(True) - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def GetAlignment(self): - """ Return the wx alignment flag for the current alignment - of the group box title. - - """ - return self._title_alignment - - def SetAlignment(self, alignment): - """ Set the alignment of the title of the group box. Should - be one of wx.ALIGN_LEFT, wx.ALIGN_RIGHT, wx.ALIGN_CENTER. - - """ - self._title_alignment = alignment - self._update_layout() - - def GetFlat(self): - """ Returns a boolean indicating whether the group box is using - a flat style. - - """ - return self._flat - - def SetFlat(self, flat): - """ Set whether or not the group box should be displayed using - a flat style. - - """ - self._flat = flat - if flat: - self._border.Show(False) - self._line.Show(True) - else: - self._border.Show(True) - self._line.Show(False) - self._update_layout() - - def GetTitle(self): - """ Return the current title text in the group box. - - """ - # Undo the hack applied in SetTitle(...) - title = self._title - if title: - title = title[1:-1] - return title - - def SetTitle(self, title): - """ Set the current title text in the group box. - - """ - # A bit of a hack to give us a little padding around the label - if title: - title = ' %s ' % title - self._title = title - self._label.SetLabel(title) - self._label_size = self._label.GetBestSize() - if not title: - self._label.Show(False) - else: - self._label.Show(True) - self._update_layout() - - def SetDimensions(self, x, y, width, height): - """ Overridden parent class method to synchronize the group - box decorations. - - """ - super(wxGroupBox, self).SetDimensions(x, y, width, height) - self._update_layout() - - def SetSize(self, size): - """ Overridden parent class method to synchronize the group - box decorations. - - """ - super(wxGroupBox, self).SetSize(size) - self._update_layout() - - def GetContentsMargins(self): - """ Get the contents margins for the group box. - - These margins are computed empirically so that they look similar - to the margins provided by Qt on Windows. - - Returns - ------- - result : tuple - The top, right, bottom, and left margin values. - - """ - label = self._label - height = label.GetCharHeight() - if not label.IsShown(): - height /= 2 - return (height, 1, 1, 1) - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def _update_layout(self): - """ Synchronizes the drawing of the group box decorations with - the panel. - - """ - if self._flat: - self._update_line_geometry() - else: - self._update_border_geometry() - self._update_title_geometry() - self.Refresh() - - def _update_border_geometry(self): - """ Updates the geometry of the border. - - """ - width, height = self.GetSizeTuple() - self._border.SetSizeWH(width, height) - - def _update_line_geometry(self): - """ Updates the geometry of the line. - - """ - y = self._label_size.GetHeight() / 2 - width, _ = self.GetSizeTuple() - self._line.SetDimensions(0, y, width, 2) - - def _update_title_geometry(self): - """ Updates the geometry of the title. - - """ - label = self._label - flat = self._flat - align = self._title_alignment - text_width, _ = self._label_size - width, _ = self.GetSizeTuple() - # These offsets are determined empirically to look similar - # in form to Qt on Windows - if align == wx.ALIGN_LEFT: - x = 0 if flat else 8 - label.Move((x, 0)) - elif align == wx.ALIGN_RIGHT: - right = width - right -= 0 if flat else 8 - x = right - text_width - label.Move((x, 0)) - elif align == wx.ALIGN_CENTER: - label.CenterOnParent(dir=wx.HORIZONTAL) - else: - raise ValueError('Invalid title alignment %s' % align) - - -class WxGroupBox(WxContainer, ProxyGroupBox): - """ A Wx implementation of an Enaml ProxyGroupBox. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxGroupBox) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Creates the underlying QGroupBox control. - - """ - self.widget = wxGroupBox(self.parent_widget()) - - def init_widget(self): - """ Initialize the underlying widget. - - """ - super(WxGroupBox, self).init_widget() - d = self.declaration - self.set_title(d.title, cm_update=False) - self.set_flat(d.flat) - self.set_title_align(d.title_align) - - #-------------------------------------------------------------------------- - # Layout Handling - #-------------------------------------------------------------------------- - @staticmethod - def margins_func(widget): - """ Get the current contents margins for the group box. - - """ - return widget.GetContentsMargins() - - #-------------------------------------------------------------------------- - # ProxyGroupBox API - #-------------------------------------------------------------------------- - def set_title(self, title, cm_update=True): - """ Update the title of the group box. - - """ - if not cm_update: - self.widget.SetTitle(title) - return - widget = self.widget - old_margins = widget.GetContentsMargins() - widget.SetTitle(title) - new_margins = widget.GetContentsMargins() - if old_margins != new_margins: - self.margins_updated() - - def set_flat(self, flat): - """ Updates the flattened appearance of the group box. - - """ - self.widget.SetFlat(flat) - - def set_title_align(self, align): - """ Updates the alignment of the title of the group box. - - """ - wx_align = WX_ALIGNMENTS[align] - self.widget.SetAlignment(wx_align) diff --git a/enaml/wx/wx_html.py b/enaml/wx/wx_html.py deleted file mode 100644 index 22a0572b3..000000000 --- a/enaml/wx/wx_html.py +++ /dev/null @@ -1,60 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx.html - -from atom.api import Typed - -from enaml.widgets.html import ProxyHtml - -from .wx_control import WxControl - - -class wxProperHtmlWindow(wx.html.HtmlWindow): - """ A custom wx Html window that returns a non-braindead best size. - - """ - _best_size = wx.Size(256, 192) - - def GetBestSize(self): - """ Returns the best size for the html window. - - """ - return self._best_size - - -class WxHtml(WxControl, ProxyHtml): - """ A Wx implementation of the Enaml ProxyHtml widget. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxProperHtmlWindow) - - #-------------------------------------------------------------------------- - # Setup Methods - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying html widget. - - """ - self.widget = wxProperHtmlWindow(self.parent_widget()) - - def init_widget(self): - """ Initialize the underlying widget. - - """ - super(WxHtml, self).init_widget() - self.set_source(self.declaration.source) - - #-------------------------------------------------------------------------- - # ProxyHtml API - #-------------------------------------------------------------------------- - def set_source(self, source): - """ Set the source of the html widget - - """ - self.widget.SetPage(source) diff --git a/enaml/wx/wx_label.py b/enaml/wx/wx_label.py deleted file mode 100644 index 57f5e91c1..000000000 --- a/enaml/wx/wx_label.py +++ /dev/null @@ -1,81 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.label import ProxyLabel - -from .wx_control import WxControl - - -ALIGN_MAP = { - 'left': wx.ALIGN_LEFT, - 'right': wx.ALIGN_RIGHT, - 'center': wx.ALIGN_CENTER, - 'justify': wx.ALIGN_LEFT, # wx doesn't support justification -} - - -ALIGN_MASK = wx.ALIGN_LEFT | wx.ALIGN_RIGHT | wx.ALIGN_CENTER - - -class WxLabel(WxControl, ProxyLabel): - """ A Wx implementation of an Enaml ProxyLabel. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wx.StaticText) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying label widget. - - """ - self.widget = wx.StaticText(self.parent_widget()) - - def init_widget(self): - """ Initialize the underlying widget. - - """ - super(WxLabel, self).init_widget() - d = self.declaration - self.set_text(d.text) - self.set_align(d.align) - self.set_vertical_align(d.vertical_align) - - #-------------------------------------------------------------------------- - # ProxyLabel API - #-------------------------------------------------------------------------- - def set_text(self, text): - """ Set the text in the underlying widget. - - """ - with self.geometry_guard(): - self.widget.SetLabel(text) - - def set_align(self, align): - """ Set the alignment of the text in the underlying widget. - - """ - widget = self.widget - style = widget.GetWindowStyle() - style &= ~ALIGN_MASK - style |= ALIGN_MAP[align] - widget.SetWindowStyle(style) - widget.Refresh() - - def set_vertical_align(self, align): - """ Set the vertical alignment of the text in the widget. - - This is not supported on Wx. - - """ - pass diff --git a/enaml/wx/wx_layout_request.py b/enaml/wx/wx_layout_request.py deleted file mode 100644 index 562ea5704..000000000 --- a/enaml/wx/wx_layout_request.py +++ /dev/null @@ -1,14 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -from wx.lib.newevent import NewCommandEvent - - -#: A custom command event that can be posted to request a layout -#: when a widget's geometry has changed. On Qt, this type of event -#: is posted and handled automatically. This fills that gap. -wxEvtLayoutRequested, EVT_COMMAND_LAYOUT_REQUESTED = NewCommandEvent() diff --git a/enaml/wx/wx_main_window.py b/enaml/wx/wx_main_window.py deleted file mode 100644 index ec9aeeb6b..000000000 --- a/enaml/wx/wx_main_window.py +++ /dev/null @@ -1,446 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.main_window import ProxyMainWindow - -from .wx_action import wxAction -from .wx_container import WxContainer -from .wx_dock_pane import WxDockPane -from .wx_menu_bar import WxMenuBar -from .wx_tool_bar import WxToolBar -from .wx_upstream import aui -from .wx_window import WxWindow - - -class wxToolBarContainer(wx.Panel): - """ A simple wx.Panel that arranges the tool bars for a main window. - - """ - # The Wx AuiToolBar is terrible and the aui code which lays out - # the tool bars is equally as bad. Unless we want to rewrite the - # entire aui libary to do docking properly, we have to accept that - # docking toolbars on wx are a no-go. That said, if the user defined - # multiple tool bars for their main window, it would be bad to only - # show one of them, which is what we would get if we had the wx.Frame - # manage the tool bars directly (since it only supports a single tool - # bar). Instead, we put all of the tool bars in a vertical sizer and - # stick the entire thing at the top of the main window layout and - # forbid it from being moved around. If better docking support is - # desired, the user would be better off with Qt. - def __init__(self, *args, **kwargs): - """ Initialize a wxToolBarContainer. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments to initialize a - wx.Panel. - - """ - super(wxToolBarContainer, self).__init__(*args, **kwargs) - self._tool_bars = [] - self.SetSizer(wx.BoxSizer(wx.VERTICAL)) - self.SetDoubleBuffered(True) - - def AddToolBar(self, tool_bar): - """ Add a tool bar to the container. - - If the tool bar already exists in this container, this will be - a no-op. The tool bar will be reparented to this container. - - Parameters - ---------- - tool_bar : wxToolBar - The wxToolBar instance to add to this container. - - """ - tool_bars = self._tool_bars - if tool_bar not in tool_bars: - tool_bars.append(tool_bar) - tool_bar.Reparent(self) - self.GetSizer().Add(tool_bar, 0, wx.EXPAND) - - def RemoveToolBar(self, tool_bar): - """ Remove a tool bar from the container. - - If the tool bar already exists in this container, this will be - a no-op. - - Parameters - ---------- - tool_bar : wxToolBar - The wxToolBar instance to remove from the container. - - """ - tool_bars = self._tool_bars - if tool_bar in tool_bars: - tool_bars.remove(tool_bar) - self.GetSizer().Detach(tool_bar) - - -class wxMainWindow(wx.Frame): - """ A wx.Frame subclass which adds MainWindow functionality. - - """ - def __init__(self, *args, **kwargs): - """ Initialize a wxMainWindow. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments necessary to initialize - a wx.Frame. - - """ - super(wxMainWindow, self).__init__(*args, **kwargs) - flags = ( - aui.AUI_MGR_DEFAULT | aui.AUI_MGR_LIVE_RESIZE | - aui.AUI_MGR_USE_NATIVE_MINIFRAMES - ) - self._manager = aui.AuiManager(self, agwFlags=flags) - self._central_widget = None - self._tool_bars = None - self._batch = False - self.Bind(wx.EVT_MENU, self.OnMenu) - self.Bind(wx.EVT_CLOSE, self.OnClose) - self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPaneClose) - self.Bind(aui.EVT_AUI_PANE_FLOATED, self.OnPaneFloated) - self.Bind(aui.EVT_AUI_PANE_DOCKED, self.OnPaneDocked) - - # Add a hidden dummy widget to the pane manager. This is a - # workaround for a Wx bug where the laying out of the central - # pane will have jitter on window resize (the computed layout - # origin of the central pane oscillates between (0, 0) and - # (1, 1)) if there are no other panes in the layout. If we - # add a hidden pane with zero size, it prevents the jitter. - self._hidden_widget = wx.Window(self) - pane = aui.AuiPaneInfo() - pane.BestSize(wx.Size(0, 0)) - pane.MinSize(wx.Size(0, 0)) - pane.Show(False) - self._manager.AddPane(self._hidden_widget, pane) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def OnPaneClose(self, event): - """ Handle the EVT_AUI_PANE_CLOSE event. - - This event gets passed on to the wxDockPane for handling. - - """ - event.GetPane().window.OnClose(event) - - def OnPaneFloated(self, event): - """ Handle the EVT_AUI_PANE_FLOATED event. - - This event gets passed on to the wxDockPane for handling. - - """ - event.GetPane().window.OnFloated(event) - - def OnPaneDocked(self, event): - """ Handle the EVT_AUI_PANE_DOCKED event. - - This event gets passed on to the wxDockPane for handling. - - """ - event.GetPane().window.OnDocked(event) - - def OnMenu(self, event): - """ The event handler for the EVT_MENU event. - - This event handler will be called when an action is triggered - in a Menu or a ToolBar. - - """ - action = wxAction.FindById(event.GetId()) - if action is not None: - if action.IsCheckable(): - action.SetChecked(event.Checked()) - action.Trigger() - - def OnClose(self, event): - """ The event handler for the EVT_CLOSE event. - - This event handler prevents the frame from being destroyed on - close. Instead it just sets the visibility to False. - - """ - self.Hide() - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def BeginBatch(self): - """ Enter batch update mode for main window updates. - - Main window updates that are performed after calling this method - will not be committed until EndBatch is called. This can be used - to reduce flicker when making updates to the MainWindow. - - """ - self._batch = True - - def EndBatch(self): - """ Exit batch update mode and process any pending updates. - - After calling this method, any pending main window updates will - be processed. - - """ - self._batch = False - self._manager.Update() - - def GetCentralWidget(self): - """ Get the central widget for the main window. - - Returns - ------- - result : wxWindow or None - The central widget for the window, or None if no central - widget is defined. - - """ - return self._central_widget - - def SetCentralWidget(self, widget): - """ Set the central widget for the main window. - - Parameters - ---------- - widget : wxWindow - The wxWindow instance to use as the central widget in the - main window. - - """ - manager = self._manager - old_widget = self._central_widget - if old_widget: - old_widget.Hide() - pane = manager.GetPane(old_widget) - if pane.IsOk(): - pane.Show(False) - manager.DetachPane(old_widget) - self._central_widget = widget - pane = aui.AuiPaneInfo().CenterPane() - manager.AddPane(widget, pane) - if not self._batch: - manager.Update() - - def SetMenuBar(self, menu_bar): - """ Set the menu bar for the main window. - - Parameters - ---------- - menu_bar : wxMenuBar - The wxMenuBar instance to add to the main window. - - """ - old_bar = self.GetMenuBar() - if old_bar is not menu_bar: - super(wxMainWindow, self).SetMenuBar(menu_bar) - # The menu bar must be refreshed after attachment - if menu_bar: - menu_bar.Update() - - def AddToolBar(self, tool_bar): - """ Add a tool bar to the main window. - - If the tool bar already exists in the main window, calling this - method is effectively a no-op. - - Parameters - ---------- - tool_bar : wxToolBar - The wxToolBar instance to add to the main window. - - """ - bars = self._tool_bars - manager = self._manager - if bars is None: - bars = self._tool_bars = wxToolBarContainer(self) - pane = aui.AuiPaneInfo().ToolbarPane().Top().Gripper(False) - manager.AddPane(bars, pane) - pane = manager.GetPane(bars) - bars.AddToolBar(tool_bar) - pane.MinSize(bars.GetBestSize()) - if not self._batch: - manager.Update() - - def RemoveToolBar(self, tool_bar): - """ Remove a tool bar from the main window. - - If the tool bar already exists in the main window, calling this - method is effectively a no-op. - - Parameters - ---------- - tool_bar : wxToolBar - The wxToolBar instance to remove from the main window. - - """ - bars = self._tool_bars - if bars is not None: - bars.RemoveToolBar(tool_bar) - tool_bar.Hide() - manager = self._manager - pane = manager.GetPane(bars) - pane.MinSize(bars.GetBestSize()) - if not self._batch: - manager.Update() - manager.Update() # 2 calls required, because Wx... - - def AddDockPane(self, dock_pane): - """ Add a dock pane to the main window. - - If the pane already exists in the main window, calling this - method is a no-op. - - Parameters - ---------- - dock_pane : wxDockPane - The wxDockPane instance to add to the main window. - - """ - manager = self._manager - pane = manager.GetPane(dock_pane) - if not pane.IsOk(): - manager.AddPane(dock_pane, dock_pane.MakePaneInfo()) - if not self._batch: - manager.Update() - - def RemoveDockPane(self, dock_pane): - """ Remove a dock pane from the main window. - - If the pane does not exist in the window, calling this method - is a no-op. - - Parameters - ---------- - dock_pane : wxDockPane - The wxDockPane instance to remove from the window. - - """ - manager = self._manager - pane = manager.GetPane(dock_pane) - if pane.IsOk(): - pane.Show(False) - manager.DetachPane(dock_pane) - if not self._batch: - manager.Update() - - -class WxMainWindow(WxWindow, ProxyMainWindow): - """ A Wx implementation of an Enaml ProxyMainWindow. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxMainWindow) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying widget wxMainWindow widget. - - """ - style = self.creation_style() - self.widget = wxMainWindow(self.parent_widget(), style=style) - - def init_layout(self): - """ Initialize the layout for the underlying widget. - - """ - # The superclass' init_layout() method is explicitly not called - # since the layout initialization for Window is not appropriate - # for MainWindow. - widget = self.widget - widget.BeginBatch() - widget.SetMenuBar(self.menu_bar()) - widget.SetCentralWidget(self.central_widget()) - for d in self.dock_panes(): - widget.AddDockPane(d) - for d in self.tool_bars(): - widget.AddToolBar(d) - widget.EndBatch() - - def destroy(self): - """ A reimplemented destructor. - - This will free any reference to the menu bar before destroying - the underlying window. Wx segfaults otherwise. - - """ - self.widget.SetMenuBar(None) - super(WxMainWindow, self).destroy() - - #-------------------------------------------------------------------------- - # Utility Methods - #-------------------------------------------------------------------------- - def menu_bar(self): - """ Get the QMenuBar widget defined for the main window. - - """ - d = self.declaration.menu_bar() - if d is not None: - return d.proxy.widget or None - - def dock_panes(self): - """ Get the QDockWidget widgets defined for the main window. - - """ - for d in self.declaration.dock_panes(): - w = d.proxy.widget - if w: - yield w - - def tool_bars(self): - """ Get the QToolBar widgets defined for the main window. - - """ - for d in self.declaration.tool_bars(): - w = d.proxy.widget - if w: - yield w - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def child_added(self, child): - """ Handle the child added event for a WxMainWindow. - - """ - if isinstance(child, WxMenuBar): - self.widget.SetMenuBar(self.menu_bar()) - elif isinstance(child, WxContainer): - self.widget.SetCentralWidget(self.central_widget()) - elif isinstance(child, WxDockPane): - self.widget.AddDockPane(child.widget) - elif isinstance(child, WxToolBar): - self.widget.AddToolBar(child.widget) - else: - super(WxMainWindow, self).child_added(child) - - def child_removed(self, child): - """ Handle the child removed event for a WxMainWindow. - - """ - if isinstance(child, WxDockPane): - self.widget.RemoveDockPane(child.widget) - elif isinstance(child, WxToolBar): - self.widget.RemoveToolBar(child.widget) - elif isinstance(child, WxContainer): - self.widget.SetCentralWidget(self.central_widget()) - elif isinstance(child, WxMenuBar): - self.widget.SetMenuBar(self.menu_bar()) - else: - super(WxMainWindow, self).child_removed(child) diff --git a/enaml/wx/wx_menu.py b/enaml/wx/wx_menu.py deleted file mode 100644 index ba5678047..000000000 --- a/enaml/wx/wx_menu.py +++ /dev/null @@ -1,734 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx -import wx.lib.newevent - -from atom.api import Typed - -from enaml.widgets.menu import ProxyMenu - -from .wx_action import WxAction, EVT_ACTION_CHANGED -from .wx_action_group import WxActionGroup -from .wx_toolkit_object import WxToolkitObject - - -#: An event emitted when the menu state changes. -wxMenuChangedEvent, EVT_MENU_CHANGED = wx.lib.newevent.NewEvent() - - -class wxMenu(wx.Menu): - """ A wx.Menu subclass which provides a more convenient api for - working with wxMenu and wxAction children. - - """ - def __init__(self, parent, *args, **kwargs): - """ Initialize a wxMenu. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments needed to initialize - a wx.Menu. - - """ - super(wxMenu, self).__init__(*args, **kwargs) - self._parent = parent - self._title = u'' - self._all_items = [] - self._menus_map = {} - self._actions_map = {} - self._enabled = True - self._bar_enabled = True - self._visible = True - self._batch = False - self._is_context_menu = False - self._id = wx.NewId() - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def _EmitChanged(self): - """ Emits the menu changed event if not in batch mode. - - """ - if not self._batch: - event = wxMenuChangedEvent() - event.SetEventObject(self) - wx.PostEvent(self, event) - - def _SetBarEnabled(self, enabled): - """ A private method called by an owner menu bar. - - Parameters - ---------- - enabled : bool - Whether or not the owner menu bar is enabled. - - """ - if self._bar_enabled != enabled: - old = self.IsEnabled() - self._bar_enabled = enabled - new = self.IsEnabled() - if old != new: - self._EmitChanged() - - def _InsertMenuItem(self, index, menu): - """ Insert a new item into the menu for the given menu. - - Parameters - ---------- - menu : wxMenu - The wxMenu instance to use as the submenu. - - Returns - ------- - result : wx.MenuItem - The menu item to use for the given menu. - - """ - text = menu.GetTitle() - menu_id = menu.GetId() - text = text or 'menu_%d' % menu_id # null text == exception - res = wx.MenuItem(self, menu_id, text, '', subMenu=menu) - res.Enable(menu.IsEnabled()) - self.InsertItem(index, res) - return res - - def _InsertActionItem(self, index, action): - """ Insert a new item into the menu for the given action. - - Parameters - ---------- - action : wxAction - The wx action for which to create a wx.MenuItem. - - Returns - ------- - result : wx.MenuItem - The menu item for the given action. - - """ - text = action.GetText() - help = action.GetStatusTip() - if action.IsSeparator(): - res = wx.MenuItem(self, wx.ID_SEPARATOR, text, help) - self.InsertItem(index, res) - else: - action_id = action.GetId() - text = text or 'action_%d' % action_id # null text == exception - if action.IsCheckable(): - # The wx.ITEM_RADIO kind doesn't behave nicely, so we - # just use the check kind and rely on the action group - # to handle the exclusive radio behavior. Changing the - # bitmap to something that looks like a radio button - # breaks the Windows theme. - kind = wx.ITEM_CHECK - res = wx.MenuItem(self, action_id, text, help, kind) - # Must instert the item before checking it, or c++ - # assertion errors are thrown - self.InsertItem(index, res) - res.Check(action.IsChecked()) - else: - kind = wx.ITEM_NORMAL - res = wx.MenuItem(self, action_id, text, help, kind) - self.InsertItem(index, res) - res.Enable(action.IsEnabled()) - return res - - def OnActionChanged(self, event): - """ The event handler for the EVT_ACTION_CHANGED event. - - This handler will be called when a child action changes. It - ensures that the new state of the child action is in sync with - the associated menu item. - - """ - event.Skip() - action = event.GetEventObject() - item = self._actions_map.get(action) - - # Fist, check for a visibility change. This requires adding or - # removing the menu item from the menu and the actions map. - visible = action.IsVisible() - if visible != bool(item): - if visible: - index = self._all_items.index(action) - n_visible = len(self._actions_map) + len(self._menus_map) - index = min(index, n_visible) - new_item = self._InsertActionItem(index, action) - self._actions_map[action] = new_item - else: - self.DestroyItem(item) - del self._actions_map[action] - return - - # If the item is invisible, there is nothing to update. - if not item: - return - - # If the item is a separator, and the separator state has - # changed, we need to build an entirely new menu item, and - # replace the existing item with the new one. - item_sep = item.IsSeparator() - action_sep = action.IsSeparator() - if item_sep or action_sep: - if item_sep != action_sep: - self.DestroyItem(item) - index = self._all_items.index(action) - n_visible = len(self._actions_map) + len(self._menus_map) - index = min(index, n_visible) - new_item = self._InsertActionItem(index, action) - self._actions_map[action] = new_item - return - - # For all other state, the menu item can be updated in-place. - item.SetItemLabel(action.GetText()) - item.SetHelp(action.GetStatusTip()) - if action.IsCheckable(): - item.SetKind(wx.ITEM_CHECK) - item.Check(action.IsChecked()) - else: - if item.IsCheckable(): - item.Check(False) - item.SetKind(wx.ITEM_NORMAL) - item.Enable(action.IsEnabled()) - - def OnMenuChanged(self, event): - """ The event hanlder for the EVT_MENU_CHANGED event. - - This handler will be called when a child menu changes. It - ensure that the new state of the child menu is in sync with - the associated menu item. - - """ - event.Skip() - menu = event.GetEventObject() - item = self._menus_map.get(menu) - - # Fist, check for a visibility change. This requires adding or - # removing the menu item from the menu and the menus map. - visible = menu.IsVisible() - if visible != bool(item): - if visible: - index = self._all_items.index(menu) - n_visible = len(self._actions_map) + len(self._menus_map) - index = min(index, n_visible) - new_item = self._InsertMenuItem(index, menu) - self._menus_map[menu] = new_item - else: - # Need to first remove the submenu or wx will destroy it. - item.SetSubMenu(None) - self.DestroyItem(item) - del self._menus_map[menu] - return - - # If the item is invisible, there is nothing to update. - if not item: - return - - # For all other state, the menu item can be updated in-place. - item.SetItemLabel(menu.GetTitle()) - item.Enable(menu.IsEnabled()) - - def OnShowContextMenu(self, event): - """ A private event handler for displaying the context menu. - - This handler is connected to the context menu event on the - parent widget when this menu is marked as a context menu. - - """ - parent = self._parent - if parent and isinstance(parent, wx.Window): - parent.PopupMenu(self) - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def BeginBatch(self): - """ Enter batch update mode for the menu. - - """ - self._batch = True - - def EndBatch(self, emit=True): - """ Exit batch update mode for the menu. - - Parameters - ---------- - emit : bool, optional - If True, emit a changed event after leaving batch mode. The - default is True. - - """ - self._batch = False - if emit: - self._EmitChanged() - - def GetId(self): - """ Get the unique wx id for this menu. - - Returns - ------- - result : int - The wx id number for this menu. - - """ - return self._id - - def GetTitle(self): - """ Get the title for the menu. - - Returns - ------- - result : unicode - The unicode title for the menu. - - """ - return self._title - - def SetTitle(self, title): - """ Set the title for the menu. - - Parameters - ---------- - title : unicode - The unicode string to use as the menu title. - - """ - if self._title != title: - self._title = title - self._EmitChanged() - - def IsEnabled(self): - """ Get whether or not the menu is enabled. - - Returns - ------- - result : bool - Whether or not the menu is enabled. - - """ - if self._bar_enabled: - return self._enabled - return False - - def SetEnabled(self, enabled): - """ Set whether or not the menu is enabled. - - Parameters - ---------- - enabled : bool - Whether or not the menu is enabled. - - """ - if self._enabled != enabled: - self._enabled = enabled - if self._bar_enabled: - self._EmitChanged() - - def IsVisible(self): - """ Get whether or not the menu is visible. - - Returns - ------- - result : bool - Whether or not the menu is visible. - - """ - return self._visible - - def SetVisible(self, visible): - """ Set whether or not the menu is visible. - - Parameters - ---------- - visible : bool - Whether or not the menu is visible. - - """ - if self._visible != visible: - self._visible = visible - self._EmitChanged() - - def IsContextMenu(self): - """ Whether this menu acts as a context menu for its parent. - - Returns - ------- - result : bool - True if this menu acts as a context menu, False otherwise. - - """ - return self._is_context_menu - - def SetContextMenu(self, context): - """ Set whether this menu acts as a context menu for its parent. - - Parameters - ---------- - context : bool - True if this menu should act as a context menu, False - otherwise. - - """ - old_context = self._is_context_menu - self._is_context_menu = context - if old_context != context: - parent = self._parent - if parent: - handler = self.OnShowContextMenu - if context: - parent.Bind(wx.EVT_CONTEXT_MENU, handler) - else: - parent.Unbind(wx.EVT_CONTEXT_MENU, handler=handler) - - def AddMenu(self, menu): - """ Add a wx menu to the Menu. - - If the menu already exists in this menu, it will be moved to - the end. - - Parameters - ---------- - menu : wxMenu - The wxMenu instance to add to this menu. - - """ - self.InsertMenu(None, menu) - - def InsertMenu(self, before, menu): - """ Insert a wx menu into the Menu. - - If the menu already exists in this menu, if will be moved to - the proper location. - - Parameters - ---------- - before : wxAction, wxMenu, or None - The item in the menu which should come directly after the - new sub-menu. - - menu : wxMenu - The wxMenu instance to insert into this menu. - - """ - all_items = self._all_items - if menu not in all_items: - if before in all_items: - index = all_items.index(before) - else: - index = len(all_items) - all_items.insert(index, menu) - if menu.IsVisible(): - max_index = len(self._actions_map) + len(self._menus_map) - index = min(index, max_index) - menu_item = self._InsertMenuItem(index, menu) - self._menus_map[menu] = menu_item - menu.Bind(EVT_MENU_CHANGED, self.OnMenuChanged) - else: - # XXX this is a potentially slow way to do things if the - # number of menus being moved around is large. But, the - # Wx apis don't appear to offer a better way, so this is - # what we get (as usual...). - self.RemoveMenu(menu) - self.InsertMenu(before, menu) - - def RemoveMenu(self, menu): - """ Remove a wx menu from the Menu. - - If the menu does not exist in the menu, this is a no-op. - - Parameters - ---------- - menu : wxMenu - The wxMenu instance to remove from this menu. - - """ - all_items = self._all_items - if menu in all_items: - all_items.remove(menu) - menu.Unbind(EVT_MENU_CHANGED, handler=self.OnMenuChanged) - menu_item = self._menus_map.pop(menu, None) - if menu_item is not None: - self.RemoveItem(menu_item) - # Set the SubMenu to None or wx will destroy it. - menu_item.SetSubMenu(None) - - def AddAction(self, action): - """ Add a wx action to the Menu. - - If the action already exists in the menu, it will be moved to - the end. - - Parameters - ---------- - action : wxAction - The wxAction instance to add to this menu. - - """ - self.InsertAction(None, action) - - def AddActions(self, actions): - """ Add multiple wx actions to the Menu. - - If an action already exists in the menu, it will be moved to - the end. - - Parameters - ---------- - actions : iterable - An iterable of wxAction instances to add to the menu. - - """ - insert = self.InsertAction - for action in actions: - insert(None, action) - - def InsertAction(self, before, action): - """ Insert a wx action into the Menu. - - If the action already exists in the menu, it will be moved to - the proper location. - - Parameters - ---------- - before : wxAction, wxMenu, or None - The item in the menu which should come directly after the - new action. - - action : wxAction - The wxAction instance to insert into this menu. - - """ - all_items = self._all_items - if action not in all_items: - if before in all_items: - index = all_items.index(before) - else: - index = len(all_items) - all_items.insert(index, action) - if action.IsVisible(): - max_index = len(self._actions_map) + len(self._menus_map) - index = min(index, max_index) - menu_item = self._InsertActionItem(index, action) - self._actions_map[action] = menu_item - action.Bind(EVT_ACTION_CHANGED, self.OnActionChanged) - else: - # XXX this is a potentially slow way to do things if the - # number of actions being moved around is large. But, the - # Wx apis don't appear to offer a better way, so this is - # what we get (as usual...). - self.RemoveAction(action) - self.InsertAction(before, action) - - def InsertActions(self, before, actions): - """ Insert multiple wx actions into the Menu. - - If an action already exists in this menu, it will be moved to - the proper location. - - Parameters - ---------- - before : wxAction, wxMenu, or None - The item in the menu which should come directly after the - new actions. - - actions : iterable - An iterable of wxAction instances to add to the menu. - - """ - insert = self.InsertAction - for action in actions: - insert(before, action) - - def RemoveAction(self, action): - """ Remove a wx action from the Menu. - - If the action does not exist in the menu, this is a no-op. - - Parameters - ---------- - action : wxAction - The wxAction instance to remove from this menu. - - """ - all_items = self._all_items - if action in all_items: - all_items.remove(action) - action.Unbind(EVT_ACTION_CHANGED, handler=self.OnActionChanged) - menu_item = self._actions_map.pop(action, None) - if menu_item is not None: - self.RemoveItem(menu_item) - - def RemoveActions(self, actions): - """ Remove multiple actions from the Menu. - - If an action does not exist in the menu, it will be ignored. - - Parameters - ---------- - actions : iterable - An iterable of wxAction instances to remove from the menu. - - """ - remove = self.RemoveAction - for action in actions: - remove(action) - - -class WxMenu(WxToolkitObject, ProxyMenu): - """ A Wx implementation of an Enaml ProxyMenu. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxMenu) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying menu widget. - - """ - self.widget = wxMenu(self.parent_widget()) - self.widget.BeginBatch() - - def init_widget(self): - """ Initialize the widget. - - """ - super(WxMenu, self).init_widget() - d = self.declaration - self.set_title(d.title) - self.set_enabled(d.enabled) - self.set_visible(d.visible) - self.set_context_menu(d.context_menu) - self.widget.EndBatch(emit=False) - - def init_layout(self): - """ Initialize the layout of the widget. - - """ - super(WxMenu, self).init_layout() - widget = self.widget - for child in self.children(): - if isinstance(child, WxMenu): - widget.AddMenu(child.widget) - elif isinstance(child, WxAction): - widget.AddAction(child.widget) - elif isinstance(child, WxActionGroup): - widget.AddActions(child.actions()) - - def destroy(self): - """ A reimplemented destructor. - - This destructor simply drops the reference to the menu and the - enaml declaration. Destroying it will cause wx to segfault. - - """ - del self.widget - del self.declaration - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def find_next_action(self, child): - """ Get the wxAction instance which follows the child. - - Parameters - ---------- - child : WxToolkitObject - The child of interest. - - Returns - ------- - result : wxAction or None - The wxAction which comes immediately after the actions of the - given child, or None if no actions follow the child. - - """ - found = False - for dchild in self.children(): - if found: - if isinstance(dchild, (WxMenu, WxAction)): - return dchild.widget - if isinstance(dchild, WxActionGroup): - acts = dchild.actions() - if len(acts) > 0: - return acts[0] - else: - found = dchild is child - - def child_added(self, child): - """ Handle the child added event for a WxMenu. - - """ - super(WxMenu, self).child_added(child) - if isinstance(child, WxMenu): - before = self.find_next_action(child) - self.widget.InsertMenu(before, child.widget) - elif isinstance(child, WxAction): - before = self.find_next_action(child) - self.widget.InsertAction(before, child.widget) - elif isinstance(child, WxActionGroup): - before = self.find_next_action(child) - self.widget.InsertActions(before, child.actions()) - - def child_removed(self, child): - """ Handle the child removed event for a WxMenu. - - """ - super(WxMenu, self).child_removed(child) - if isinstance(child, WxMenu): - self.widget.RemoveMenu(child.widget) - elif isinstance(child, WxAction): - self.widget.RemoveAction(child.widget) - elif isinstance(child, WxActionGroup): - self.widget.RemoveActions(child.actions()) - - #-------------------------------------------------------------------------- - # ProxyMenu API - #-------------------------------------------------------------------------- - def set_title(self, title): - """ Set the title of the underlyling control. - - """ - self.widget.SetTitle(title) - - def set_visible(self, visible): - """ Set the visibility on the underlying widget. - - """ - self.widget.SetVisible(visible) - - def set_enabled(self, enabled): - """ Set the enabled state of the widget. - - """ - self.widget.SetEnabled(enabled) - - def set_context_menu(self, context): - """ Set whether or not the menu is a context menu. - - """ - self.widget.SetContextMenu(context) - - def popup(self): - """ Popup the menu at the current mouse location. - - """ - # This is not supported on wx. Wx requires the menu to be - # popped up over a specified window. It can't be done using - # global coordinates. - pass - - def close(self): - """ This is not supported in wx. - - """ - raise NotImplementedError diff --git a/enaml/wx/wx_menu_bar.py b/enaml/wx/wx_menu_bar.py deleted file mode 100644 index 6c6bccbe4..000000000 --- a/enaml/wx/wx_menu_bar.py +++ /dev/null @@ -1,268 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.menu_bar import ProxyMenuBar - -from .wx_menu import WxMenu, EVT_MENU_CHANGED -from .wx_toolkit_object import WxToolkitObject - - -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) - - -class WxMenuBar(WxToolkitObject, ProxyMenuBar): - """ A Wx implementation of an Enaml ProxyMenuBar. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxMenuBar) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying menu bar widget. - - """ - # Wx behaves better when creating the menu bar without a parent. - self.widget = wxMenuBar() - - def init_layout(self): - """ Initialize the layout for the menu bar. - - """ - super(WxMenuBar, self).init_layout() - widget = self.widget - for child in self.children(): - if isinstance(child, WxMenu): - widget.AddMenu(child.widget) - - def destroy(self): - """ A reimplemented destructor. - - This destructor simply drops the reference to the menu bar and - the enaml declaration and clears the menus in the menu bar. - Destroying it will cause wx to segfault. - - """ - if self.widget: - self.widget.SetMenus([]) - del self.widget - del self.declaration - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def find_next_menu(self, child): - """ Get the wxMenu instance which follows the child. - - Parameters - ---------- - child : WxMenu - The child menu of interest. - - Returns - ------- - result : wxMenu or None - The wxMenu which comes immediately after the actions of the - given child, or None if no actions follow the child. - - """ - found = False - for dchild in self.children(): - if found: - if isinstance(dchild, WxMenu): - return dchild.widget - else: - found = dchild is child - - def child_added(self, child): - """ Handle the child added event for a WxMenuBar. - - """ - super(WxMenuBar, self).child_added(child) - if isinstance(child, WxMenu): - before = self.find_next_menu(child) - self.widget.InsertMenu(before, child.widget) - - def child_removed(self, child): - """ Handle the child removed event for a WxMenuBar. - - """ - super(WxMenuBar, self).child_removed(child) - if isinstance(child, WxMenu): - self.widget.RemoveMenu(child.widget) diff --git a/enaml/wx/wx_mpl_canvas.py b/enaml/wx/wx_mpl_canvas.py deleted file mode 100644 index d7bbbebf0..000000000 --- a/enaml/wx/wx_mpl_canvas.py +++ /dev/null @@ -1,94 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from enaml.widgets.mpl_canvas import ProxyMPLCanvas - -from .wx_control import WxControl - -from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg -from matplotlib.backends.backend_wx import NavigationToolbar2Wx - - -class WxMPLCanvas(WxControl, ProxyMPLCanvas): - """ A Wx implementation of an Enaml MPLCanvas. - - """ - #-------------------------------------------------------------------------- - # Setup Methods - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying widget. - - """ - widget = wx.Panel(self.parent_widget()) - sizer = wx.BoxSizer(wx.VERTICAL) - widget.SetSizer(sizer) - self.widget = widget - - def init_layout(self): - """ Initialize the layout of the underlying widget. - - """ - super(WxMPLCanvas, self).init_layout() - self._refresh_mpl_widget() - - #-------------------------------------------------------------------------- - # Message Handlers - #-------------------------------------------------------------------------- - def set_figure(self, figure): - """ Set the MPL figure for the widget. - - """ - with self.geometry_guard(): - self._refresh_mpl_widget() - - def set_toolbar_visible(self, visible): - """ Set the toolbar visibility for the widget. - - """ - widget = self.widget - sizer = widget.GetSizer() - children = sizer.GetChildren() - if len(children) == 2: - with self.geometry_guard(): - widget.Freeze() - toolbar = children[0] - toolbar.Show(visible) - sizer.Layout() - widget.Thaw() - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def _refresh_mpl_widget(self): - """ Create the mpl widget and update the underlying control. - - """ - # Delete the old widgets in the layout, it's just shenanigans - # to try to reuse the old widgets when the figure changes. - widget = self.widget - widget.Freeze() - sizer = widget.GetSizer() - sizer.Clear(True) - - # Create the new figure and toolbar widgets. It seems that key - # events will not be processed without an mpl figure manager. - # However, a figure manager will create a new toplevel window, - # which is certainly not desired in this case. This appears to - # be a limitation of matplotlib. - figure = self.declaration.figure - if figure: - canvas = FigureCanvasWxAgg(widget, -1, figure) - toolbar = NavigationToolbar2Wx(canvas) - toolbar.Show(self.declaration.toolbar_visible) - sizer.Add(toolbar, 0, wx.EXPAND) - sizer.Add(canvas, 1, wx.EXPAND) - - sizer.Layout() - widget.Thaw() diff --git a/enaml/wx/wx_notebook.py b/enaml/wx/wx_notebook.py deleted file mode 100644 index d5ca90357..000000000 --- a/enaml/wx/wx_notebook.py +++ /dev/null @@ -1,511 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import weakref -import wx - -from atom.api import Instance - -from enaml.widgets.notebook import ProxyNotebook - -from .wx_constraints_widget import WxConstraintsWidget -from .wx_layout_request import EVT_COMMAND_LAYOUT_REQUESTED -from .wx_page import WxPage -from .wx_upstream import aui - - -#: A mapping of notebook tab positions for the document style tabs. -#: Wx currently only supports top and bottom tab positions. -_TAB_POSITION_MAP = { - 'top': aui.AUI_NB_TOP, - 'left': aui.AUI_NB_TOP, - 'bottom': aui.AUI_NB_BOTTOM, - 'right': aui.AUI_NB_BOTTOM, -} - - -#: A mask of notebook tab positions for the document style tabs. -_TAB_POSITION_MASK = aui.AUI_NB_TOP | aui.AUI_NB_BOTTOM - - -class wxDocumentNotebook(aui.AuiNotebook): - """ A custom AuiNotebook which handles children of type wxPage. - - This notebook is used to implement 'document' style tabs for an - Enaml Notebook control. - - """ - def __init__(self, *args, **kwargs): - """ Initialize a wxDocumentNotebook. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments to pass to the super - class. - - """ - super(wxDocumentNotebook, self).__init__(*args, **kwargs) - self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnPageClose) - self._hidden_pages = weakref.WeakKeyDictionary() - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def OnPageClose(self, event): - """ The handler for the EVT_AUINOTEBOOK_PAGE_CLOSE event. - - This handler forwards the event to the wxPage instance. - - """ - self.GetPage(event.GetSelection()).OnClose(event) - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def GetBestSize(self): - """ Overridden GetBestSize method which will return the best - size for the notebook. - - """ - size = wx.Size(256, 192) - for idx in xrange(self.GetPageCount()): - page = self.GetPage(idx) - psize = page.GetBestSize() - size.SetWidth(max(size.GetWidth(), psize.GetWidth())) - size.SetHeight(max(size.GetHeight(), psize.GetHeight())) - # On windows, there's an off by 2 error in the width. - height = self.GetHeightForPageHeight(size.GetHeight()) - return wx.Size(size.GetWidth() + 2, height) - - def ShowWxPage(self, page): - """ Show a hidden wxPage instance in the notebook. - - If the page is not owned by the notebook, this is a no-op. - - Parameters - ---------- - page : wxPage - The hidden wxPage instance to show in the notebook. - - """ - index = self.GetPageIndex(page) - if index == -1: - index = self._hidden_pages.pop(page, -1) - if index != -1: - self.InsertWxPage(index, page) - - def HideWxPage(self, page): - """ Hide the given wxPage instance in the notebook. - - If the page is not owned by the notebook, this is a no-op. - - Parameters - ---------- - page : wxPage - The wxPage instance to hide in the notebook. - - """ - index = self.GetPageIndex(page) - if index != -1: - self.RemovePage(index) - page.Show(False) - self._hidden_pages[page] = index - - def AddWxPage(self, page): - """ Add a wxPage instance to the notebook. - - This should be used in favor of AddPage for adding a wxPage - instance to the notebook, as it takes into account the current - page state. - - Parameters - ---------- - page : wxPage - The wxPage instance to add to the notebook. - - """ - if page.IsOpen(): - self.AddPage(page, page.GetTitle()) - index = self.GetPageIndex(page) - if not page.GetEnabled(): - self.EnableTab(index, False) - if not page.GetClosable(): - self.SetCloseButton(index, False) - else: - page.Show(False) - self._hidden_pages[page] = self.GetPageCount() - - def InsertWxPage(self, index, page): - """ Insert a wxPage instance into the notebook. - - This should be used in favor of InsertPage for inserting a - wxPage instance into the notebook, as it takes into account the - current page state. - - Parameters - ---------- - index : int - The index at which to insert the page. - - page : wxPage - The wxPage instance to add to the notebook. - - """ - if page.IsOpen(): - index = min(index, self.GetPageCount()) - self.InsertPage(index, page, page.GetTitle()) - if not page.GetEnabled(): - self.EnableTab(index, False) - if not page.GetClosable(): - self.SetCloseButton(index, False) - else: - page.Show(False) - self._hidden_pages[page] = index - - def RemoveWxPage(self, page): - """ Remove a wxPage instance from the notebook. - - If the page does not exist in the notebook, this is a no-op. - - Parameters - ---------- - page : wxPage - The wxPage instance to remove from the notebook. - - """ - index = self.GetPageIndex(page) - if index != -1: - self.RemovePage(index) - page.Show(False) - - -class wxPreferencesNotebook(wx.Notebook): - """ A custom wx.Notebook which handles children of type wxPage. - - This notebook is used to implement 'document' style tabs for an - Enaml Notebook control. - - """ - def __init__(self, *args, **kwargs): - """ Initialize a wxPreferencesNotebook. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments to pass to the super - class. - - """ - super(wxPreferencesNotebook, self).__init__(*args, **kwargs) - self._hidden_pages = weakref.WeakKeyDictionary() - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def GetBestSize(self): - """ Overridden GetBestSize method which will return the best - size for the notebook. - - """ - size = wx.Size(256, 192) - for idx in xrange(self.GetPageCount()): - page = self.GetPage(idx) - psize = page.GetBestSize() - size.SetWidth(max(size.GetWidth(), psize.GetWidth())) - size.SetHeight(max(size.GetHeight(), psize.GetHeight())) - # On windows, the wx.Notebook renders each page with 2 pixels - # of padding on the top, and bottom, and 4 pixels of padding - # on the left and right (at least under the Windows 7 theme). - # We need to compensate for this padding along with the space - # taken up by the tab bar. The tab bar height was manually - # measured to be 21 pixels. I've found no way to have wx measure - # it for me (there's nothing in RendererNative for it), so its - # just hard-coded for now. - return wx.Size(size.GetWidth() + 8, size.GetHeight() + 25) - - def ShowWxPage(self, page): - """ Show a hidden wxPage instance in the notebook. - - If the page is not owned by the notebook, this is a no-op. - - Parameters - ---------- - page : wxPage - The hidden wxPage instance to show in the notebook. - - """ - index = self.GetPageIndex(page) - if index == -1: - index = self._hidden_pages.pop(page, -1) - if index != -1: - self.InsertWxPage(index, page) - - def HideWxPage(self, page): - """ Hide the given wxPage instance in the notebook. - - If the page is not owned by the notebook, this is a no-op. - - Parameters - ---------- - page : wxPage - The wxPage instance to hide in the notebook. - - """ - index = self.GetPageIndex(page) - if index != -1: - self.RemovePage(index) - page.Show(False) - self._hidden_pages[page] = index - - def AddWxPage(self, page): - """ Add a wxPage instance to the notebook. - - This should be used in favor of AddPage for adding a wxPage - instance to the notebook, as it takes into account the current - page state. - - Parameters - ---------- - page : wxPage - The wxPage instance to add to the notebook. - - """ - if page.IsOpen(): - self.AddPage(page, page.GetTitle()) - else: - page.Show(False) - self._hidden_pages[page] = self.GetPageCount() - - def InsertWxPage(self, index, page): - """ Insert a wxPage instance into the notebook. - - This should be used in favor of InsertPage for inserting a - wxPage instance into the notebook, as it takes into account the - current page state. - - Parameters - ---------- - index : int - The index at which to insert the page. - - page : wxPage - The wxPage instance to add to the notebook. - - """ - if page.IsOpen(): - index = min(index, self.GetPageCount()) - self.InsertPage(index, page, page.GetTitle()) - else: - page.Show(False) - self._hidden_pages[page] = index - - def RemoveWxPage(self, page): - """ Remove a wxPage instance from the notebook. - - If the page does not exist in the notebook, this is a no-op. - - Parameters - ---------- - page : wxPage - The wxPage instance to remove from the notebook. - - """ - index = self.GetPageIndex(page) - if index != -1: - self.RemovePage(index) - page.Show(False) - - def GetPageIndex(self, page): - """ Returns the index of the page in the control. - - Parameters - ---------- - page : wxPage - The wxPage instance in the control. - - Returns - ------- - result : int - The index of the page in the control, or -1 if the page - is not found. - - """ - # Wx has no way of querying for the index of a page, so we must - # linear search ourselves. Hooray for brain-dead toolkits! - for idx in xrange(self.GetPageCount()): - if self.GetPage(idx) == page: - return idx - return -1 - - def EnableTab(self, index, enabled): - """ Change the enabled state of the tab at the given index. - - Parameters - ---------- - index : int - The index of the target tab. - - enabled : bool - Whether or not the tab should be enabled. - - """ - if index >= 0 and index < self.GetPageCount(): - page = self.GetPage(index) - page.Enable(enabled) - - def SetCloseButton(self, index, closable): - """ A dummy method which makes the wxPreferencesNotebook api - compatible with the wxDocumentNotebook. - - Close buttons cannot be set on a preferences notebook. This - method exists soley so that child wxPages do not need to - special case their implementation based on their parent. - - """ - pass - - -class WxNotebook(WxConstraintsWidget, ProxyNotebook): - """ A Wx implementation of an Enaml ProxyNotebook. - - """ - #: A reference to the widget created by the proxy. - widget = Instance((wxPreferencesNotebook, wxDocumentNotebook)) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying wx notebook widget. - - """ - if self.declaration.tab_style == 'preferences': - w = wxPreferencesNotebook(self.parent_widget()) - else: - style = aui.AUI_NB_SCROLL_BUTTONS - w = wxDocumentNotebook(self.parent_widget(), agwStyle=style) - self.widget = w - - def init_widget(self): - """ Create and initialize the notebook control - - """ - super(WxNotebook, self).init_widget() - d = self.declaration - self.set_tab_style(d.tab_style) - self.set_tab_position(d.tab_position) - self.set_tabs_closable(d.tabs_closable) - self.set_tabs_movable(d.tabs_movable) - - def init_layout(self): - """ Handle the layout initialization for the notebook. - - """ - super(WxNotebook, self).init_layout() - widget = self.widget - for page in self.pages(): - widget.AddWxPage(page) - widget.Bind(EVT_COMMAND_LAYOUT_REQUESTED, self.on_layout_requested) - - #-------------------------------------------------------------------------- - # Utility Methods - #-------------------------------------------------------------------------- - def pages(self): - """ Get the pages defined for the notebook. - - """ - for p in self.declaration.pages(): - yield p.proxy.widget or None - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def child_added(self, child): - """ Handle the child added event for a WxNotebook. - - """ - super(WxNotebook, self).child_added(child) - if isinstance(child, WxPage): - for index, dchild in enumerate(self.children()): - if child is dchild: - self.widget.InsertWxPage(index, child.widget) - - def child_removed(self, child): - """ Handle the child removed event for a WxNotebook. - - """ - super(WxNotebook, self).child_removed(child) - if isinstance(child, WxPage): - self.widget.RemoveWxPage(child.widget) - self.geometry_updated() - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_layout_requested(self, event): - """ Handle the layout request event from a child page. - - """ - self.geometry_updated() - - #-------------------------------------------------------------------------- - # ProxyNotebook API - #-------------------------------------------------------------------------- - def set_tab_style(self, style): - """ Set the tab style for the underlying widget. - - """ - # Changing the tab style on wx is not supported - pass - - def set_tab_position(self, position): - """ Set the position of the tab bar in the widget. - - """ - # Tab position changes only supported on the document notebook. - widget = self.widget - if isinstance(widget, wxDocumentNotebook): - flags = widget.GetAGWWindowStyleFlag() - flags &= ~_TAB_POSITION_MASK - flags |= _TAB_POSITION_MAP[position] - widget.SetAGWWindowStyleFlag(flags) - widget.Refresh() # Avoids rendering artifacts - - def set_tabs_closable(self, closable): - """ Set whether or not the tabs are closable. - - """ - # Closable tabs are only supported on the document notebook. - widget = self.widget - if isinstance(widget, wxDocumentNotebook): - flags = widget.GetAGWWindowStyleFlag() - if closable: - flags |= aui.AUI_NB_CLOSE_ON_ALL_TABS - else: - flags &= ~aui.AUI_NB_CLOSE_ON_ALL_TABS - widget.SetAGWWindowStyleFlag(flags) - - def set_tabs_movable(self, movable): - """ Set whether or not the tabs are movable. - - """ - # Movable tabs are only supported on the document notebook. - widget = self.widget - if isinstance(widget, wxDocumentNotebook): - flags = widget.GetAGWWindowStyleFlag() - if movable: - flags |= aui.AUI_NB_TAB_MOVE - else: - flags &= ~aui.AUI_NB_TAB_MOVE - widget.SetAGWWindowStyleFlag(flags) - - def set_size_hint_mode(self, mode): - """ This is not supported on Wx. - - """ - pass diff --git a/enaml/wx/wx_page.py b/enaml/wx/wx_page.py deleted file mode 100644 index 64d24749f..000000000 --- a/enaml/wx/wx_page.py +++ /dev/null @@ -1,352 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx -import wx.lib.newevent - -from atom.api import Typed - -from enaml.widgets.page import ProxyPage - -from .wx_container import WxContainer -from .wx_widget import WxWidget -from .wx_single_widget_sizer import wxSingleWidgetSizer - - -#: An event emitted when the notebook page is closed. -wxPageClosedEvent, EVT_PAGE_CLOSED = wx.lib.newevent.NewEvent() - - -class wxPage(wx.Panel): - """ A wxPanel subclass which acts as a page in a wx notebook. - - """ - def __init__(self, *args, **kwargs): - """ Initialize a wxPage. - - Parameters - ---------- - *args, **kwargs - The position and keyword arguments required to initialize - a wxContainer. - - """ - super(wxPage, self).__init__(*args, **kwargs) - self._title = u'' - self._closable = True - self._is_enabled = True - self._is_open = True - self._page_widget = None - self.SetSizer(wxSingleWidgetSizer()) - self.Bind(wx.EVT_SHOW, self.OnShow) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def OnClose(self, event): - """ Handle the page close event. - - This event handler is called by the parent notebook. The parent - event is always be vetoed or else Wx will destroy the page. If - the page is closable, we close the page and emit the custom - close event. - - """ - event.Veto() - if self.GetClosable(): - self.Close() - evt = wxPageClosedEvent() - wx.PostEvent(self, evt) - - def OnShow(self, event): - """ Handle the show event. - - Wx will not emit an EVT_SHOW on the child of this page. So, this - event handler passes the show event along to the contained page - widget, so that it can disable its layout when not visible. - - """ - page = self._page_widget - if page: - wx.PostEvent(page, event) - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def _PageIndexOperation(self, closure): - """ A private method which will run the given closure if there - is a valid index for this page. - - """ - parent = self.GetParent() - if parent: - index = parent.GetPageIndex(self) - if index != -1: - closure(parent, index) - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def GetPageWidget(self): - """ Get the page widget for this page. - - Returns - ------- - result : wxWindow or None - The page widget being managed by this page. - - """ - return self._page_widget - - def SetPageWidget(self, widget): - """ Set the page widget for this page. - - Parameters - ---------- - widget : wxWindow - The wx widget to use as the page widget in this page. - - """ - self._page_widget = widget - self.GetSizer().Add(widget) - - def IsOpen(self): - """ Get whether or not the page is open. - - Returns - ------- - result : bool - True if the page is open, False otherwise. - - """ - return self._is_open - - def Open(self): - """ Open the page in the notebook. - - """ - self._is_open = True - parent = self.GetParent() - if parent: - parent.ShowWxPage(self) - - def Close(self): - """ Close the page in the notebook. - - """ - self._is_open = False - parent = self.GetParent() - if parent: - parent.HideWxPage(self) - - def GetEnabled(self): - """ Get the enabled state of the page. - - This method should be used in favor of IsEnabled. - - Returns - ------- - result : bool - True the page is enabled, False otherwise. - - """ - return self._is_enabled - - def SetEnabled(self, enabled): - """ Set the enabled state of the page. - - This method should be used in favor of Enable. - - Parameters - --------- - enabled : bool - Whether or not the page should be enabled. - - """ - self._is_enabled = enabled - def closure(nb, index): - nb.EnableTab(index, enabled) - self._PageIndexOperation(closure) - - def GetTitle(self): - """ Returns tab title for this page. - - Returns - ------- - result : unicode - The title string for the page's tab. - - """ - return self._title - - def SetTitle(self, title): - """ Set the title for this page. - - Parameters - ---------- - title : unicode - The string to use for this page's tab title. - - """ - self._title = title - def closure(nb, index): - nb.SetPageText(index, title) - self._PageIndexOperation(closure) - - def GetClosable(self): - """ Returns whether or not this page is closable. - - Returns - ------- - result : bool - True if this page is closable, False otherwise. - - """ - return self._closable - - def SetClosable(self, closable): - """ Set whether this page is closable. - - Parameters - ---------- - closable : bool - True if this page should be closable, False otherwise. - - """ - self._closable = closable - def closure(nb, index): - nb.SetCloseButton(index, closable) - self._PageIndexOperation(closure) - - -class WxPage(WxWidget, ProxyPage): - """ A Wx implementation of an Enaml notebook ProxyPage. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxPage) - - #-------------------------------------------------------------------------- - # Setup Methods - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying wxPage widget. - - """ - self.widget = wxPage(self.parent_widget()) - - def init_widget(self): - """ Create and initialize the page control. - - """ - super(WxPage, self).init_widget() - d = self.declaration - self.set_title(d.title) - self.set_closable(d.closable) - if d.icon: - self.set_icon(d.icon) - self.widget.Bind(EVT_PAGE_CLOSED, self.on_page_closed) - - def init_layout(self): - """ Initialize the layout of the notebook page. - - """ - super(WxPage, self).init_layout() - self.widget.SetPageWidget(self.page_widget()) - - #-------------------------------------------------------------------------- - # Utility Methods - #-------------------------------------------------------------------------- - def page_widget(self): - """ Find and return the page widget child for this widget. - - """ - p = self.declaration.page_widget() - if p is not None: - return p.proxy.widget or None - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def child_added(self, child): - """ Handle the child added event for a WxPage. - - """ - super(WxPage, self).child_removed(child) - if isinstance(child, WxContainer): - self.widget.SetPageWidget(self.page_widget()) - - def child_removed(self, child): - """ Handle the child removed event for a WxPage. - - """ - super(WxPage, self).child_removed(child) - if isinstance(child, WxContainer): - self.widget.SetPageWidget(self.page_widget()) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_page_closed(self, event): - """ The event handler for the EVT_PAGE_CLOSED event. - - """ - self.declaration._handle_close() - - #-------------------------------------------------------------------------- - # ProxyPage API - #-------------------------------------------------------------------------- - def set_visible(self, visible): - """ An overridden visibility setter which to opens|closes the - notebook page. - - """ - if visible: - self.widget.Open() - else: - self.widget.Close() - - def ensure_visible(self): - """ An overridden visibility setter which to opens|closes the - notebook page. - - """ - self.set_visible(True) - - def ensure_hidden(self): - """ An overridden visibility setter which to opens|closes the - notebook page. - - """ - self.set_visible(False) - - def set_enabled(self, enabled): - """ An overridden enabled setter which sets the tab enabled - state. - - """ - self.widget.SetEnabled(enabled) - - def set_title(self, title): - """ Set the title of the tab for this page. - - """ - self.widget.SetTitle(title) - - def set_icon(self, icon): - """ Sets the widget's icon to the provided image. - - This is not supported on Wx. - - """ - pass - - def set_closable(self, closable): - """ Set whether or not this page is closable. - - """ - self.widget.SetClosable(closable) diff --git a/enaml/wx/wx_progress_bar.py b/enaml/wx/wx_progress_bar.py deleted file mode 100644 index 1c6ea9d53..000000000 --- a/enaml/wx/wx_progress_bar.py +++ /dev/null @@ -1,74 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.progress_bar import ProxyProgressBar - -from .wx_control import WxControl - - -class WxProgressBar(WxControl, ProxyProgressBar): - """ A Wx implementation of an Enaml ProxyProgressBar. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wx.Gauge) - - #-------------------------------------------------------------------------- - # Setup Methods - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying wx.Gauge widget. - - """ - self.widget = wx.Gauge(self.parent_widget()) - - def init_widget(self): - """ Create and initialize the progress bar control. - - """ - super(WxProgressBar, self).init_widget() - d = self.declaration - self.set_minimum(d.minimum) - self.set_maximum(d.maximum) - self.set_value(d.value) - self.set_text_visible(d.text_visible) - - #-------------------------------------------------------------------------- - # ProxyProgressBar API - #-------------------------------------------------------------------------- - def set_minimum(self, value): - """ Set the minimum value of the progress bar - - """ - d = self.declaration - self.widget.SetRange(d.maximum - value) - - def set_maximum(self, value): - """ Set the maximum value of the progress bar - - """ - d = self.declaration - self.widget.SetRange(value - d.minimum) - - def set_value(self, value): - """ Set the value of the progress bar - - """ - d = self.declaration - self.widget.SetValue(value - d.minimum) - - def set_text_visible(self, visible): - """ Set the text visibility on the widget. - - This is not implemented on Wx. - - """ - pass diff --git a/enaml/wx/wx_push_button.py b/enaml/wx/wx_push_button.py deleted file mode 100644 index ff4942e79..000000000 --- a/enaml/wx/wx_push_button.py +++ /dev/null @@ -1,70 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.push_button import ProxyPushButton - -from .wx_abstract_button import WxAbstractButton - - -class WxPushButton(WxAbstractButton, ProxyPushButton): - """ A Wx implementation of the Enaml ProxyPushButton. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wx.Button) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying wxButton widget. - - """ - self.widget = wx.Button(self.parent_widget()) - - def init_widget(self): - """ Handle layout initialization for the push button. - - """ - super(WxPushButton, self).init_widget() - self.widget.Bind(wx.EVT_BUTTON, self.on_clicked) - - #-------------------------------------------------------------------------- - # Abstract API Implementation - #-------------------------------------------------------------------------- - def set_checkable(self, checkable): - """ Sets whether or not the widget is checkable. - - This is not supported on Wx. - - """ - pass - - def get_checked(self): - """ Returns the checked state of the widget. - - """ - return False - - def set_checked(self, checked): - """ Sets the widget's checked state with the provided value. - - """ - pass - - #-------------------------------------------------------------------------- - # ProxyPushButton API - #-------------------------------------------------------------------------- - def set_default(self, default): - """ This is not supported on Wx. - - """ - pass diff --git a/enaml/wx/wx_radio_button.py b/enaml/wx/wx_radio_button.py deleted file mode 100644 index 956ab96c7..000000000 --- a/enaml/wx/wx_radio_button.py +++ /dev/null @@ -1,206 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -from weakref import WeakKeyDictionary - -import wx -import wx.lib.newevent - -from atom.api import Typed - -from enaml.widgets.radio_button import ProxyRadioButton - -from .wx_abstract_button import WxAbstractButton, CHECKED_GUARD - - -#: A radio button event that is emited when the button is clicked. -wxRadioClicked, EVT_RADIO_CLICKED = wx.lib.newevent.NewEvent() - -#: A radio button event emitted when the button value is changed. -wxRadioToggled, EVT_RADIO_TOGGLED = wx.lib.newevent.NewEvent() - - -class wxProperRadioButton(wx.RadioButton): - """ A custom stubclass of wx.RadioButton. - - The wx.RadioButton doesn't emit toggled events when it unchecks the - other radio buttons in the same group. So, the only time an - EVT_RADIOBUTTON is emitted is when the button changes from off to - on. This custom subclass does some orchestration and will emit an - EVT_RADIO_TOGGLED whenever the control changes its value. It also - emits an EVT_RADIO_CLICKED event when the control is clicked, even - if the click doesn't change the value in the control. - - """ - #: The WeakKeyDictionary which stores the sibling radio buttons - #: for a given parent widget. When any radio button is toggled, - #: the list of siblings is iterated and each child is given the - #: the chance to see it's been toggled off. If it has, then it - #: will emit a toggled event. - _parents = WeakKeyDictionary() - - def __init__(self, *args, **kwargs): - """ Initialize a wxProperRadioButton. - - *args, **kwargs - The positional and keyword arguments required to initialize - a wx.RadioButton. - - """ - super(wxProperRadioButton, self).__init__(*args, **kwargs) - parent = self.GetParent() - if parent: - children = self._parents.setdefault(parent, []) - children.append(self) - self._last = self.GetValue() - self._in_click = False - self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) - self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) - self.Bind(wx.EVT_RADIOBUTTON, self.OnToggled) - - def OnLeftDown(self, event): - """ Handles the left down mouse event for the radio button. - - This is first part of generating a click event. - - """ - event.Skip() - self._in_click = True - - def OnLeftUp(self, event): - """ Handles the left up mouse event for the radio button. - - This is the second part of generating a click event. - - """ - event.Skip() - if self._in_click: - self._in_click = False - event = wxRadioClicked() - wx.PostEvent(self, event) - - def OnToggled(self, event): - """ Handles the standard toggle event and emits a toggle on - event. After emitting that event, it will cycle through the - list of its siblings and give them a change to emit a toggle - off event. - - """ - self._last = self.GetValue() - event = wxRadioToggled() - wx.PostEvent(self, event) - self.CheckSiblings() - - def CheckToggledOff(self): - """ Checks the state of the radio button to see if it has been - toggled from on to off. If it has, it will emit a toggle off - event. - - """ - last = self._last - curr = self.GetValue() - if not curr and last: - self._last = curr - event = wxRadioToggled() - wx.PostEvent(self, event) - - def CheckSiblings(self): - """ Iterates over the siblings of this radio button, giving - each a chance to respond to a possible toggle off. - - """ - parent = self.GetParent() - if parent: - parents = self._parents - if parent in parents: - for child in parents[parent]: - child.CheckToggledOff() - - def SetValue(self, val): - """ Overrides the default SetValue method to emit proper events. - - """ - old = self.GetValue() - if old != val: - super(wxProperRadioButton, self).SetValue(val) - self._last = val - event = wxRadioToggled() - wx.PostEvent(self, event) - self.CheckSiblings() - - def Destroy(self): - """ Overridden destroy method to remove the radio button from - the list of siblings before it's destroyed. - - """ - parent = self.GetParent() - if parent: - parents = self._parents - if parent in parents: - children = parents[parent] - try: - children.remove(self) - except ValueError: - pass - super(wxProperRadioButton, self).Destroy() - - -class WxRadioButton(WxAbstractButton, ProxyRadioButton): - """ A Wx implementation of an Enaml ProxyRadioButton. - - WxRadioButton uses a custom wx.RadioButton control. Radio buttons - with the same parent will be mutually exclusive. For independent - groups, place them in their own parent component. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxProperRadioButton) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Creates the underlying custom wx.RadioButton control. - - """ - self.widget = wxProperRadioButton(self.parent_widget()) - - def init_widget(self): - """ Initialize the radio button control. - - """ - super(WxRadioButton, self).init_widget() - widget = self.widget - widget.Bind(EVT_RADIO_CLICKED, self.on_clicked) - widget.Bind(EVT_RADIO_TOGGLED, self.on_toggled) - - #-------------------------------------------------------------------------- - # Abstract API Implementation - #-------------------------------------------------------------------------- - def set_checkable(self, checkable): - """ Sets whether or not the widget is checkable. - - This is not supported in Wx. - - """ - pass - - def get_checked(self): - """ Returns the checked state of the widget. - - """ - return self.widget.GetValue() - - def set_checked(self, checked): - """ Sets the widget's checked state with the provided value. - - """ - self._guard |= CHECKED_GUARD - try: - self.widget.SetValue(checked) - finally: - self._guard &= ~CHECKED_GUARD diff --git a/enaml/wx/wx_resource_helpers.py b/enaml/wx/wx_resource_helpers.py deleted file mode 100644 index 3af53d42c..000000000 --- a/enaml/wx/wx_resource_helpers.py +++ /dev/null @@ -1,226 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from enaml.fontext import FontStyle - - -FONT_STYLE = { - FontStyle.Normal: wx.FONTSTYLE_NORMAL, - FontStyle.Italic: wx.FONTSTYLE_ITALIC, - FontStyle.Oblique: wx.FONTSTYLE_SLANT, -} - - -# ASPECT_RATIO_MODE = { -# 'ignore': Qt.IgnoreAspectRatio, -# 'keep': Qt.KeepAspectRatio, -# 'keep_by_expanding': Qt.KeepAspectRatioByExpanding -# } - - -# TRANSFORM_MODE = { -# 'fast': Qt.FastTransformation, -# 'smooth': Qt.SmoothTransformation -# } - - -# ICON_MODE = { -# 'normal': QIcon.Normal, -# 'disabled': QIcon.Disabled, -# 'active': QIcon.Active, -# 'selected': QIcon.Selected, -# } - - -# ICON_STATE = { -# 'off': QIcon.Off, -# 'on': QIcon.On, -# } - - -# def QImage_from_Image(image): -# """ Convert an Enaml Image into a QImage. - -# Parameters -# ---------- -# image : Image -# The Enaml Image object. - -# Returns -# ------- -# result : QImage -# The QImage instance for the given Enaml image. - -# """ -# format = image.format -# if format == 'auto': -# format = '' -# qimage = QImage.fromData(image.data, format) -# if -1 not in image.size and not qimage.isNull(): -# qsize = QSize(*image.size) -# if qsize != qimage.size(): -# mode = ASPECT_RATIO_MODE[image.aspect_ratio_mode] -# transform = TRANSFORM_MODE[image.transform_mode] -# qimage = qimage.scaled(qsize, mode, transform) -# return qimage - - -# def get_cached_qimage(image): -# """ Get the cached QImage for the Enaml Image. - -# Parameters -# ---------- -# image : Image -# The Enaml Image object. - -# Returns -# ------- -# result : QImage -# The cached QImage for the image. If no cached image exists, one -# will be created. - -# """ -# qimage = image._tkdata -# if not isinstance(qimage, QImage): -# qimage = image._tkdata = QImage_from_Image(image) -# return qimage - - -# def QIcon_from_Icon(icon): -# """ Convert the given Enaml Icon into a QIcon. - -# Parameters -# ---------- -# icon : Icon -# The Enaml Icon object. - -# Returns -# ------- -# result : QIcon -# The QIcon instance for the given Enaml icon. - -# """ -# qicon = QIcon() -# for icon_image in icon.images: -# image = icon_image.image -# if not image: -# continue -# mode = ICON_MODE[icon_image.mode] -# state = ICON_STATE[icon_image.state] -# qimage = get_cached_qimage(image) -# qpixmap = QPixmap.fromImage(qimage) -# qicon.addPixmap(qpixmap, mode, state) -# return qicon - - -# def get_cached_qicon(icon): -# """ Get the cached QIcon for the Enaml Icon. - -# Parameters -# ---------- -# icon : Icon -# The Enaml Icon object. - -# Returns -# ------- -# result : QIcon -# The cached QIcon for the icon. If no cached icon exists, one -# will be created. - -# """ -# qicon = icon._tkdata -# if not isinstance(qicon, QIcon): -# qicon = icon._tkdata = QIcon_from_Icon(icon) -# return qicon - - -def wxColor_from_Color(color): - """ Convert the given Enaml Color into a wxColor. - - Parameters - ---------- - color : Color - The Enaml Color object. - - Returns - ------- - result : wxColor - The wxColor instance for the given Enaml color. - - """ - return wx.Color(color.red, color.green, color.blue, color.alpha) - - -def get_cached_wxcolor(color): - """ Get the cached QColor for the Enaml Color. - - Parameters - ---------- - color : Color - The Enaml Color object. - - Returns - ------- - result : QColor - The cached QColor for the color. If no cached color exists, one - will be created. - - """ - wxcolor = color._tkdata - if not isinstance(wxcolor, wx.Color): - wxcolor = color._tkdata = wxColor_from_Color(color) - return wxcolor - - -def wxFont_from_Font(font): - """ Convert the given Enaml Font into a wxFont. - - Parameters - ---------- - font : Font - The Enaml Font object. - - Returns - ------- - result : wxFont - The wxFont instance for the given Enaml font. - - """ - wxstyle = FONT_STYLE[font.style] - if font.weight < 50: - wxweight = wx.FONTWEIGHT_LIGHT - elif font.weight >= 75: - wxweight = wx.FONTWEIGHT_BOLD - else: - wxweight = wx.FONTWEIGHT_NORMAL - wxfamily = wx.FONTFAMILY_DEFAULT - wxfont = wx.Font(font.pointsize, wxfamily, wxstyle, wxweight) - wxfont.SetFaceName(font.family) - return wxfont - - -def get_cached_wxfont(font): - """ Get the cached wxFont for the Enaml Font. - - Parameters - ---------- - font : Font - The Enaml Font object. - - Returns - ------- - result : wxFont - The cached wxFont for the font. If no cached font exists, one - will be created. - - """ - wxfont = font._tkdata - if not isinstance(wxfont, wx.Font): - wxfont = font._tkdata = wxFont_from_Font(font) - return wxfont diff --git a/enaml/wx/wx_scroll_area.py b/enaml/wx/wx_scroll_area.py deleted file mode 100644 index 88d71a4b1..000000000 --- a/enaml/wx/wx_scroll_area.py +++ /dev/null @@ -1,233 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.scroll_area import ProxyScrollArea - -from .wx_container import WxContainer -from .wx_frame import WxFrame -from .wx_single_widget_sizer import wxSingleWidgetSizer - - -# The 'always_on' scroll policy is not supported on wx, because it -# requires setting a window style flag which does not dynamically -# toggle in a reliable fashion. Since we only support 'off' or 'auto' -# it's easiest to use this mapping to convert straight from policy -# values into a respective scroll rate. A rate of Zero causes wx not -# to show the scroll bar. A positive rate indicates to scroll that many -# pixels per event. We set the rate to 1 to have smooth scrolling. Wx -# doesn't make a distinction between scroll events caused by the mouse -# or scrollbar and those caused by clicking the scroll buttons (ala qt), -# and thus this rate applies the same to all of those events. Since we -# expect that clicking on a scroll button happens much more infrequently -# than scrolling by dragging the scroll bar, we opt for a lower rate -# in order to get smooth drag scrolling and sacrifice some usability -# on the scroll buttons. -SCROLLBAR_MAP = { - 'as_needed': 1, - 'always_off': 0, - 'always_on': 1, -} - - -class wxScrollAreaSizer(wxSingleWidgetSizer): - """ A wxSingleWidgetSizer subclass which makes adjusts the min - size to account for a 2 pixel error in Wx. - - """ - def CalcMin(self): - """ Returns the minimum size for the area owned by the sizer. - - Returns - ------- - result : wxSize - The wx size representing the minimum area required by the - sizer. - - """ - # The effective min size computation is correct, but the wx - # scrolled window interprets it with an error of 2px. That - # is we need to make wx think that the min size is 2px smaller - # than it actually is so that scroll bars should and hide at - # the appropriate sizes. - res = super(wxScrollAreaSizer, self).CalcMin() - if res.IsFullySpecified(): - res.width -= 2 - res.height -= 2 - return res - - def RecalcSizes(self): - """ Resizes the child to fit the available space of the window. - - This takes into account the maximum allowed size of the widget. - - """ - widget = self.GetWidget() - if widget: - size = self.GetSize() - size.DecTo(self.CalcMax()) - widget.SetSize(size) - - -class wxScrollArea(wx.ScrolledWindow): - """ A custom wx.ScrolledWindow which is suits Enaml's use case. - - """ - #: The internal best size. The same as QAbstractScrollArea. - _best_size = wx.Size(256, 192) - - def __init__(self, *args, **kwargs): - """ Initialize a wxScrollArea. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments needed to initialize - a wxScrolledWindow. - - """ - super(wxScrollArea, self).__init__(*args, **kwargs) - self._scroll_widget = None - self.SetSizer(wxScrollAreaSizer()) - - def GetBestSize(self): - """ An overridden parent class method which returns a sensible - best size. - - The default wx implementation returns a best size of (16, 16) - on Windows; far too small to be useful. So, we just adopt the - size hint of (256, 192) used in Qt's QAbstractScrollArea. - - """ - return self._best_size - - def GetScrollWidget(self): - """ Get the scroll widget for this scroll area. - - Returns - ------- - results : wxWindow - The wxWindow being scrolled by this scroll area. - - """ - return self._scroll_widget - - def SetScrollWidget(self, widget): - """ Set the scroll widget for this scroll area. - - Parameters - ---------- - widget : wxWindow - The wxWindow which should be scrolled by this area. - - """ - self._scroll_widget = widget - self.GetSizer().Add(widget) - - -class WxScrollArea(WxFrame, ProxyScrollArea): - """ A Wx implementation of an Enaml ScrollArea. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxScrollArea) - - def create_widget(self): - """ Create the underlying wxScrolledWindow widget. - - """ - style = wx.HSCROLL | wx.VSCROLL | wx.BORDER_SIMPLE - self.widget = wxScrollArea(self.parent_widget(), style=style) - - def init_widget(self): - """ Initialize the underlying widget. - - """ - super(WxScrollArea, self).init_widget() - d = self.declaration - self.set_horizontal_policy(d.horizontal_policy) - self.set_vertical_policy(d.vertical_policy) - self.set_widget_resizable(d.widget_resizable) - - def init_layout(self): - """ Handle the layout initialization for the scroll area. - - """ - super(WxScrollArea, self).init_layout() - self.widget.SetScrollWidget(self.scroll_widget()) - - #-------------------------------------------------------------------------- - # Utility Methods - #-------------------------------------------------------------------------- - def scroll_widget(self): - """ Find and return the scroll widget child for this widget. - - """ - w = self.declaration.scroll_widget() - if w is not None: - return w.proxy.widget or None - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def child_added(self, child): - """ Handle the child added event for a WxScrollArea. - - """ - super(WxScrollArea, self).child_added(child) - if isinstance(child, WxContainer): - self.widget.SetScrollWidget(self.scroll_widget()) - - def child_removed(self, child): - """ Handle the child removed event for a WxScrollArea. - - """ - super(WxScrollArea, self).child_removed(child) - if isinstance(child, WxContainer): - self.widget.SetScrollWidget(self.scroll_widget()) - - #-------------------------------------------------------------------------- - # Overrides - #-------------------------------------------------------------------------- - def replace_constraints(self, old_cns, new_cns): - """ A reimplemented WxConstraintsWidget layout method. - - Constraints layout may not cross the boundary of a ScrollArea, - so this method is no-op which stops the layout propagation. - - """ - pass - - #-------------------------------------------------------------------------- - # ProxyScrollArea API - #-------------------------------------------------------------------------- - def set_horizontal_policy(self, policy): - """ Set the horizontal scrollbar policy of the widget. - - """ - horiz = SCROLLBAR_MAP[policy] - vert = SCROLLBAR_MAP[self.declaration.vertical_policy] - self.widget.SetScrollRate(horiz, vert) - - def set_vertical_policy(self, policy): - """ Set the vertical scrollbar policy of the widget. - - """ - horiz = SCROLLBAR_MAP[self.declaration.horizontal_policy] - vert = SCROLLBAR_MAP[policy] - self.widget.SetScrollRate(horiz, vert) - - def set_widget_resizable(self, resizable): - """ Set whether or not the scroll widget is resizable. - - This is not supported on Wx. - - """ - pass diff --git a/enaml/wx/wx_single_widget_sizer.py b/enaml/wx/wx_single_widget_sizer.py deleted file mode 100644 index 6e428f4c7..000000000 --- a/enaml/wx/wx_single_widget_sizer.py +++ /dev/null @@ -1,74 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - - -class wxSingleWidgetSizer(wx.PySizer): - """ A custom wx Sizer for sizing a single child widget. - - There can only be one widget in this sizer at a time and it should - be added via the .Add(...) method. Old items will be removed - automatically (but not destroyed). - - """ - _default_size = wx.Size(-1, -1) - - _widget = None - - def CalcMax(self): - """ A method to compute the maximum size allowed by the sizer. - - This is not a native wx sizer method, but is included for - convenience. - - """ - widget = self._widget - if not widget: - return self._default_size - return widget.GetMaxSize() - - def GetWidget(self): - """ Get a reference tot he underlying widget. - - """ - return self._widget - - def Add(self, widget): - """ Adds the given widget to the sizer, removing the old widget - if present. The old widget is not destroyed. - - """ - if self._widget is not widget: - self.Clear(deleteWindows=False) - old = self._widget - if old: - old.Hide() - self._widget = widget - if widget: - widget.Show() - res = super(wxSingleWidgetSizer, self).Add(widget) - self.Layout() - return res - - def CalcMin(self): - """ Returns the minimum size for the children this sizer is - managing. - - """ - widget = self._widget - if not widget: - return self._default_size - return widget.GetEffectiveMinSize() - - def RecalcSizes(self): - """ Resizes the child to fit the available space of the window. - - """ - widget = self._widget - if widget: - widget.SetSize(self.GetSize()) diff --git a/enaml/wx/wx_slider.py b/enaml/wx/wx_slider.py deleted file mode 100644 index e2d0444cf..000000000 --- a/enaml/wx/wx_slider.py +++ /dev/null @@ -1,279 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx -import wx.lib.newevent - -from atom.api import Int, Typed - -from enaml.widgets.slider import ProxySlider - -from .wx_control import WxControl - - -#: Horizontal tick mapping -_TICK_POSITION_MAP = { - 'top': wx.SL_TOP | wx.SL_AUTOTICKS, - 'bottom': wx.SL_BOTTOM | wx.SL_AUTOTICKS, - 'left': wx.SL_LEFT | wx.SL_AUTOTICKS, - 'right': wx.SL_RIGHT | wx.SL_AUTOTICKS, - 'both': wx.SL_BOTH | wx.SL_AUTOTICKS, -} - - -#: An OR'd combination of all the tick flags. -_TICK_MASK = ( - wx.SL_TOP | wx.SL_BOTTOM | wx.SL_LEFT | wx.SL_RIGHT | wx.SL_BOTH | - wx.SL_AUTOTICKS -) - - -#: A map adapting orientation to tick positions -_TICK_ADAPT_MAP = { - 'vertical': { - 'left': 'left', - 'right': 'right', - 'both': 'both', - 'top': 'left', - 'bottom': 'right', - }, - 'horizontal': { - 'left': 'top', - 'right': 'bottom', - 'both': 'both', - 'top': 'top', - 'bottom': 'bottom', - }, -} - - -#: A map from string orientation to wx slider orientation -_ORIENTATION_MAP = { - 'horizontal': wx.SL_HORIZONTAL, - 'vertical': wx.SL_VERTICAL, -} - - -#: An OR'd combination of all the orientation flags -_ORIENTATION_MASK = wx.SL_HORIZONTAL | wx.SL_VERTICAL - - -#: A new event emitted by the custom slider control -wxSliderEvent, EVT_SLIDER = wx.lib.newevent.NewEvent() - - -class wxProperSlider(wx.Slider): - """ A wx.Slider subclass which supports tracking. - - """ - #: The event types for the frequent thumb track event - _tracking_evt = wx.EVT_SCROLL_THUMBTRACK.evtType[0] - - #: The event type for the thumb release event. - _release_evt = wx.EVT_SCROLL_THUMBRELEASE.evtType[0] - - #: The event type for the scroll end event. - _end_evt = wx.EVT_SCROLL_CHANGED.evtType[0] - - def __init__(self, *args, **kwargs): - """ Initialize a wxProperSlider. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments for initializing a - wx.Slider. - - """ - super(wxProperSlider, self).__init__(*args, **kwargs) - self._tracking = True - self.Bind(wx.EVT_SCROLL, self.OnScroll) - - def OnScroll(self, event): - """ An event handler which handles all scroll events. - - This handler determines whether or not a slider event sould be - emitted for the scroll changed, based on whether tracking is - enabled for the slider. - - """ - evt_type = event.EventType - - # We never emit on the _end_event since that is windows-only - if evt_type == self._end_evt: - return - - if self._tracking: - if evt_type != self._release_evt: - emit = True - else: - emit = False - else: - emit = evt_type != self._tracking_evt - - if emit: - evt = wxSliderEvent() - wx.PostEvent(self, evt) - - def GetTracking(self): - """ Whether or not tracking is enabled for the slider. - - Returns - ------- - result : bool - True if tracking is enabled for the slider, False otherwise. - - """ - return self._tracking - - def SetTracking(self, tracking): - """ Set whether tracking is enabled for the slider. - - Parameters - ---------- - tracking : bool - True if tracking should be enabled, False otherwise. - - """ - self._tracking = tracking - - -#: A cyclic guard flag -VALUE_FLAG = 0x1 - - -class WxSlider(WxControl, ProxySlider): - """ A Wx implementation of an Enaml ProxySlider. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxProperSlider) - - #: Cyclic notification guard flags. - _guard = Int(0) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying wxProperSlider widget. - - """ - self.widget = wxProperSlider(self.parent_widget()) - - def init_widget(self): - """ Initialize the underlying widget. - - """ - # NOTE: The tick interval must be set *after* the tick position - # or Wx will ignore the tick interval. grrr... - super(WxSlider, self).init_widget() - d = self.declaration - self.set_minimum(d.minimum) - self.set_maximum(d.maximum) - self.set_value(d.value) - self.set_orientation(d.orientation) - self.set_page_step(d.page_step) - self.set_single_step(d.single_step) - self.set_tick_position(d.tick_position) - self.set_tick_interval(d.tick_interval) - self.set_tracking(d.tracking) - self.widget.Bind(EVT_SLIDER, self.on_value_changed) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_value_changed(self, event): - """ Send the 'value_changed' action to the Enaml widget when the - slider value has changed. - - """ - if not self._guard & VALUE_FLAG: - self._guard |= VALUE_FLAG - try: - self.declaration.value = self.widget.GetValue() - finally: - self._guard &= ~VALUE_FLAG - - #-------------------------------------------------------------------------- - # ProxySlider API - #-------------------------------------------------------------------------- - def set_value(self, value): - """ Set the value of the underlying widget. - - """ - if not self._guard & VALUE_FLAG: - self._guard |= VALUE_FLAG - try: - self.widget.SetValue(value) - finally: - self._guard &= ~VALUE_FLAG - - def set_maximum(self, maximum): - """ Set the maximum value of the underlying widget. - - """ - widget = self.widget - minimum, _ = widget.GetRange() - widget.SetRange(minimum, maximum) - - def set_minimum(self, minimum): - """ Set the minimum value of the underlying widget. - - """ - widget = self.widget - _, maximum = widget.GetRange() - widget.SetRange(minimum, maximum) - - def set_orientation(self, orientation): - """ Set the orientation of the underlying widget. - - """ - widget = self.widget - style = widget.GetWindowStyle() - style &= ~_ORIENTATION_MASK - style |= _ORIENTATION_MAP[orientation] - widget.SetWindowStyle(style) - - def set_page_step(self, page_step): - """ Set the page step of the underlying widget. - - """ - self.widget.SetPageSize(page_step) - - def set_single_step(self, single_step): - """ Set the single step of the underlying widget. - - """ - self.widget.SetLineSize(single_step) - - def set_tick_interval(self, interval): - """ Set the tick interval of the underlying widget. - - """ - self.widget.SetTickFreq(interval) - - def set_tick_position(self, tick_position): - """ Set the tick position of the underlying widget. - - """ - widget = self.widget - style = widget.GetWindowStyle() - style &= ~_TICK_MASK - if tick_position != 'no_ticks': - if style & wx.SL_VERTICAL: - tick_position = _TICK_ADAPT_MAP['vertical'][tick_position] - else: - tick_position = _TICK_ADAPT_MAP['horizontal'][tick_position] - style |= _TICK_POSITION_MAP[tick_position] - widget.SetWindowStyle(style) - - def set_tracking(self, tracking): - """ Set the tracking of the underlying widget. - - """ - self.widget.SetTracking(tracking) diff --git a/enaml/wx/wx_spin_box.py b/enaml/wx/wx_spin_box.py deleted file mode 100644 index c2b356927..000000000 --- a/enaml/wx/wx_spin_box.py +++ /dev/null @@ -1,550 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx -import wx.lib.newevent - -from atom.api import Int, Typed - -from enaml.widgets.spin_box import ProxySpinBox - -from .wx_control import WxControl - - -#: The changed event for the custom spin box -wxSpinBoxEvent, EVT_SPIN_BOX = wx.lib.newevent.NewEvent() - - -class wxProperSpinBox(wx.SpinCtrl): - """ A custom wx spin control that acts more like QSpinBox. - - The standard wx.SpinCtrl doesn't support too many features, and - the ones it does support are (like wrapping) are limited. So, - this custom control hard codes the internal range to the maximum - range of the wx.SpinCtrl and implements wrapping manually. - - For changed events, users should bind to EVT_SPIN_BOX rather than - EVT_SPINCTRL. - - See the method docstrings for supported functionality. - - This control is really a god awful hack and needs to be rewritten - using a combination wx.SpinButton and wx.TextCtrl. - - """ - def __init__(self, *args, **kwargs): - """ CustomSpinCtrl constructor. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments for initializing a - wx.SpinCtrl. - - """ - # The max range of the wx.SpinCtrl is the range of a signed - # 32bit integer. We don't care about wx's internal value of - # the control, since we maintain our own internal counter. - # and because the internal value of the widget gets reset to - # the minimum of the range whenever SetValueString is called. - self._hard_min = -(1 << 31) - self._hard_max = (1 << 31) - 1 - self._internal_value = 0 - self._low = 0 - self._high = 100 - self._step = 1 - self._prefix = u'' - self._suffix = u'' - self._special_value_text = u'' - self._value_string = unicode(self._low) - self._wrap = False - self._read_only = False - - # Stores whether spin-up or spin-down was pressed. - self._spin_state = None - - super(wxProperSpinBox, self).__init__(*args, **kwargs) - super(wxProperSpinBox, self).SetRange(self._hard_min, self._hard_max) - - # Setting the spin control to process the enter key removes - # its processing of the Tab key. This is desired for two reasons: - # 1) It is consistent with the Qt version of the control. - # 2) The default tab processing is kinda wacky in that when - # tab is pressed, it emits a text event with the string - # representation of the integer value of the control, - # regardless of the value of the user supplied string. - # This is definitely not correct and so processing on - # Enter allows us to avoid the issue entirely. - self.WindowStyle |= wx.TE_PROCESS_ENTER - - self.Bind(wx.EVT_SPIN_UP, self.OnSpinUp) - self.Bind(wx.EVT_SPIN_DOWN, self.OnSpinDown) - self.Bind(wx.EVT_SPINCTRL, self.OnSpinCtrl) - self.Bind(wx.EVT_TEXT, self.OnText) - self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) - self.Bind(wx.EVT_TEXT_ENTER, self.OnEnterPressed) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def OnEnterPressed(self, event): - """ The event handler for an enter key press. It forces an - interpretation of the current text control value. - - """ - self.InterpretText() - - def OnKillFocus(self, event): - """ Handles evaluating the text in the control when the control - loses focus. - - """ - # The spin control doesn't emit a spin event when losing focus - # to process typed input change unless it results in a different - # value, so we have to handle it manually and update the control - # again after the event. It must be invoked on a CallAfter or it - # doesn't work properly. The lambda avoids a DeadObjectError if - # the app is exited before the callback executes. - wx.CallAfter(lambda: self.InterpretText() if self else None) - - def OnText(self, event): - """ Handles the text event of the spin control to store away the - user typed text for later conversion. - - """ - if self._read_only: - return - # Do not be tempted to try to implement the 'tracking' feature - # by adding logic to this method. Wx emits this event at weird - # times such as ctrl-a select all as well as when SetValueString - # is called. Granted, this can be avoided with a recursion guard, - # however, there is no way to get/set the caret position on the - # control and every call to SetValueString resets the caret - # position to Zero. So, there is really no possible way to - # implement 'tracking' without creating an entirely new custom - # control. So for now, the wx backend just lacks that feature. - self._value_string = event.GetString() - - def OnSpinUp(self, event): - """ The event handler for the spin up event. We veto the spin - event to prevent the control from changing it's internal value. - Instead, we maintain complete control of the value. - - """ - event.Veto() - if self._read_only: - return - self._spin_state = 'up' - self.OnSpinCtrl(event) - self._spin_state = None - - def OnSpinDown(self, event): - """ The event handler for the spin down event. We veto the spin - event to prevent the control from changing it's internal value. - Instead, we maintain complete control of the value. - - """ - event.Veto() - if self._read_only: - return - self._spin_state = 'down' - self.OnSpinCtrl(event) - self._spin_state = None - - def OnSpinCtrl(self, event): - """ Handles the spin control being changed by user interaction. - All of the manual stepping and wrapping logic is computed by - this method. - - """ - if self._read_only: - return - last = self._internal_value - low = self._low - high = self._high - step = self._step - wrap = self._wrap - spin_state = self._spin_state - if spin_state == 'down': - if last == low: - if wrap: - computed = high - else: - computed = low - else: - computed = last - step - if computed < low: - computed = low - self.SetValue(computed) - elif spin_state == 'up': - if last == high: - if wrap: - computed = low - else: - computed = high - else: - computed = last + step - if computed > high: - computed = high - self.SetValue(computed) - else: - # A suprious spin event generated by wx when the widget loses - # focus. We can safetly ignore it. - pass - - #-------------------------------------------------------------------------- - # Getters/Setters - #-------------------------------------------------------------------------- - def GetLow(self): - """ Returns the minimum value of the control. - - """ - return self._low - - def GetMin(self): - """ Equivalent to GetLow(). - - """ - return self._low - - def SetLow(self, low): - """ Sets the minimum value of the control and changes the - value to the min if the current value would be out of range. - - """ - if low < self._hard_min: - raise ValueError('%s is too low for wxProperSpinBox.' % low) - self._low = low - if self.GetValue() < low: - self.SetValue(low) - - def GetHigh(self): - """ Returns the maximum value of the control. - - """ - return self._high - - def GetMax(self): - """ Equivalent to GetHigh(). - - """ - return self._high - - def SetHigh(self, high): - """ Sets the maximum value of the control and changes the - value to the max if the current value would be out of range. - - """ - if high > self._hard_max: - raise ValueError('%s is too high for wxProperSpinBox.' % high) - self._high = high - if self.GetValue() > high: - self.SetValue(high) - - def SetRange(self, low, high): - """ Sets the low and high values of the control. - - """ - self.SetLow(low) - self.SetHigh(high) - - def GetStep(self): - """ Returns the step size of the control. - - """ - return self._step - - def SetStep(self, step): - """ Sets the step size of the control. - - """ - self._step = step - - def GetWrap(self): - """ Gets the wrap flag of the control. - - """ - return self._wrap - - def SetWrap(self, wrap): - """ Sets the wrap flag of the control. - - """ - self._wrap = wrap - - def GetPrefix(self): - """ Get the prefix text for the control. - - Returns - ------- - result : unicode - The unicode prefix text. - - """ - return self._prefix - - def SetPrefix(self, prefix): - """ Set the prefix text for the control. - - Parameters - ---------- - prefix : unicode - The unicode prefix text for the control. - - """ - self._prefix = prefix - - def GetSuffix(self): - """ Get the suffix text for the control. - - Returns - ------- - result : unicode - The unicode suffix text. - - """ - return self._suffix - - def SetSuffix(self, suffix): - """ Set the suffix text for the control. - - Parameters - ---------- - suffix : unicode - The unicode suffix text for the control. - - """ - self._suffix = suffix - - def GetSpecialValueText(self): - """ Returns the special value text for the spin box. - - Returns - ------- - result : unicode - The unicode special value text. - - """ - return self._special_value_text - - def SetSpecialValueText(self, text): - """ Set the special value text for the control. - - Parameters - ---------- - text : unicode - The unicode special value text for the control. - - """ - self._special_value_text = text - - def GetReadOnly(self): - """ Get the read only flag for the control. - - Returns - ------- - result : bool - True if the control is read only, False otherwise. - - """ - return self._suffix - - def SetReadOnly(self, read_only): - """ Set the read only flag for the control - - Parameters - ---------- - read_only : bool - True if the control should be read only, False otherwise. - - """ - self._read_only = read_only - - def GetValue(self): - """ Returns the internal integer value of the control. - - """ - return self._internal_value - - def SetValue(self, value): - """ Sets the value of the control to the given value, provided - that the value is within the range of the control. If the - given value is within range, and is different from the current - value of the control, an EVT_SPIN_BOX will be emitted. - - """ - different = False - if self._low <= value <= self._high: - different = (self._internal_value != value) - self._internal_value = value - - # Always set the value string, just to be overly - # safe that we don't fall out of sync. - self._value_string = self.TextFromValue(self._internal_value) - self.SetValueString(self._value_string) - - if different: - evt = wxSpinBoxEvent() - wx.PostEvent(self, evt) - - #-------------------------------------------------------------------------- - # Support Methods - #-------------------------------------------------------------------------- - def InterpretText(self): - """ Interprets the user supplied text and updates the control. - - """ - prefix = self._prefix - suffix = self._suffix - svt = self._special_value_text - text = self._value_string - if svt and text == svt: - self.SetValue(self._low) - return - if prefix and text.startswith(prefix): - text = text[len(prefix):] - if suffix and text.endswith(suffix): - text = text[:-len(suffix)] - try: - value = int(text) - except ValueError: - value = self._internal_value - self.SetValue(value) - - def TextFromValue(self, value): - """ Converts the given integer to a string for display. - - """ - prefix = self._prefix - suffix = self._suffix - svt = self._special_value_text - if value == self._low and svt: - return svt - text = unicode(value) - if prefix: - text = '%s%s' % (prefix, text) - if suffix: - text = '%s%s' % (text, suffix) - return text - - -#: Cyclic guard flag -VALUE_FLAG = 0x1 - - -class WxSpinBox(WxControl, ProxySpinBox): - """ A Wx implementation of an Enaml ProxySpinBox. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxProperSpinBox) - - #: Cyclic guard flags - _guard = Int(0) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying wxProperSpinBox widget. - - """ - self.widget = wxProperSpinBox(self.parent_widget()) - - def init_widget(self, ): - """ Create and initialize the slider control. - - """ - super(WxSpinBox, self).init_widget() - d = self.declaration - self.set_maximum(d.maximum) - self.set_minimum(d.minimum) - self.set_value(d.value) - self.set_prefix(d.prefix) - self.set_suffix(d.suffix) - self.set_special_value_text(d.special_value_text) - self.set_single_step(d.single_step) - self.set_read_only(d.read_only) - self.set_wrapping(d.wrapping) - self.widget.Bind(EVT_SPIN_BOX, self.on_value_changed) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_value_changed(self, event): - """ The event handler for the 'EVT_SPIN_BOX' event. - - """ - if not self._guard & VALUE_FLAG: - self._guard |= VALUE_FLAG - try: - self.declaration.value = self.widget.GetValue() - finally: - self._guard &= ~VALUE_FLAG - - #-------------------------------------------------------------------------- - # ProxySpinBox API - #-------------------------------------------------------------------------- - def set_maximum(self, maximum): - """ Set the widget's maximum value. - - """ - self.widget.SetHigh(maximum) - - def set_minimum(self, minimum): - """ Set the widget's minimum value. - - """ - self.widget.SetLow(minimum) - - def set_value(self, value): - """ Set the spin box's value. - - """ - if not self._guard & VALUE_FLAG: - self._guard |= VALUE_FLAG - try: - self.widget.SetValue(value) - finally: - self._guard &= ~VALUE_FLAG - - - def set_prefix(self, prefix): - """ Set the prefix for the spin box. - - """ - self.widget.SetPrefix(prefix) - - def set_suffix(self, suffix): - """ Set the suffix for the spin box. - - """ - self.widget.SetSuffix(suffix) - - def set_special_value_text(self, text): - """ Set the special value text for the spin box. - - """ - self.widget.SetSpecialValueText(text) - - def set_single_step(self, step): - """ Set the widget's single step value. - - """ - self.widget.SetStep(step) - - def set_read_only(self, read_only): - """ Set the widget's read only flag. - - """ - self.widget.SetReadOnly(read_only) - - def set_wrapping(self, wrapping): - """ Set the widget's wrapping flag. - - """ - self.widget.SetWrap(wrapping) diff --git a/enaml/wx/wx_split_item.py b/enaml/wx/wx_split_item.py deleted file mode 100644 index 532549bd8..000000000 --- a/enaml/wx/wx_split_item.py +++ /dev/null @@ -1,166 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.split_item import ProxySplitItem - -from .wx_single_widget_sizer import wxSingleWidgetSizer -from .wx_container import WxContainer -from .wx_widget import WxWidget - - -class wxSplitItem(wx.Panel): - """ A wxPanel subclass which acts as an item in a wxSplitter. - - """ - def __init__(self, parent): - """ Initialize a wxSplitItem. - - Parameters - ---------- - parent : wx.Window - The parent widget of the split item. - - """ - super(wxSplitItem, self).__init__(parent) - self._split_widget = None - self._stretch = 0 - self.SetSizer(wxSingleWidgetSizer()) - - def GetSplitWidget(self): - """ Get the split widget for this split item. - - Returns - ------- - result : wxWindow or None - The split widget being managed by this item. - - """ - return self._split_widget - - def SetSplitWidget(self, widget): - """ Set the split widget for this split item. - - Parameters - ---------- - widget : wxWindow - The wxWindow to use as the split widget in this item. - - """ - self._split_widget = widget - self.GetSizer().Add(widget) - - def GetStretch(self): - """ Get the stretch factor for the widget. - - Returns - ------- - result : int - The stretch factor for the widget. - - """ - return self._stretch - - def SetStretch(self, stretch): - """ Set the stretch factor for the widget. - - Parameters - ---------- - stretch : int - The stretch factor for the widget. - - """ - self._stretch = stretch - - -class WxSplitItem(WxWidget, ProxySplitItem): - """ A Wx implementation of an Enaml ProxySplitItem. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxSplitItem) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the underlying QStackItem widget. - - """ - self.widget = wxSplitItem(self.parent_widget()) - - def init_widget(self): - """ Initialize the underyling widget. - - """ - super(WxSplitItem, self).init_widget() - d = self.declaration - self.set_stretch(d.stretch) - self.set_collapsible(d.collapsible) - - def init_layout(self): - """ Initialize the layout for the underyling widget. - - """ - super(WxSplitItem, self).init_layout() - self.widget.SetSplitWidget(self.split_widget()) - - #-------------------------------------------------------------------------- - # Utility Methods - #-------------------------------------------------------------------------- - def split_widget(self): - """ Find and return the split widget child for this widget. - - Returns - ------- - result : wxWindow or None - The split widget defined for this widget, or None if one is - not defined. - - """ - d = self.declaration.split_widget() - if d is not None: - return d.proxy.widget or None - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def child_added(self, child): - """ Handle the child added event for a WxSplitItem. - - """ - super(WxSplitItem, self).child_added(child) - if isinstance(child, WxContainer): - self.widget.SetSplitWidget(self.split_widget()) - - def child_removed(self, child): - """ Handle the child removed event for a WxSplitItem. - - """ - super(WxSplitItem, self).child_removed(child) - if isinstance(child, WxContainer): - self.widget.SetSplitWidget(self.split_widget()) - - #-------------------------------------------------------------------------- - # ProxySplitItem API - #-------------------------------------------------------------------------- - def set_stretch(self, stretch): - """ Set the stretch factor for the underlying widget. - - """ - self.widget.SetStretch(stretch) - - def set_collapsible(self, collapsible): - """ Set the collapsible flag for the underlying widget. - - This is not supported on wx. - - """ - pass diff --git a/enaml/wx/wx_splitter.py b/enaml/wx/wx_splitter.py deleted file mode 100644 index 58a611590..000000000 --- a/enaml/wx/wx_splitter.py +++ /dev/null @@ -1,270 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx -from wx.lib.splitter import MultiSplitterWindow - -from atom.api import Typed - -from enaml.widgets.splitter import ProxySplitter - -from .wx_constraints_widget import WxConstraintsWidget -from .wx_split_item import WxSplitItem - - -_ORIENTATION_MAP = { - 'horizontal': wx.HORIZONTAL, - 'vertical': wx.VERTICAL, -} - - -class wxSplitter(MultiSplitterWindow): - """ A wx.lib.splitter.MultiSplitterWindow subclass that changes - the behavior of resizing neighbors to be consistent with Qt. - - """ - def _OnMouse(self, event): - """ Overriden parent class mouse event handler which fakes the - state of the keyboard so that resize behavior is consistent - between wx and Qt. - - """ - # We modify the mouse event to "fake" like the shift key is - # always down. This causes the splitter to not adjust its - # neighbor when dragging the sash. This behavior is consistent - # with Qt's behavior. This is not *the best* way to handle this, - # but it's the easiest and quickest at the moment. The proper - # way would be to reimplement this method in its entirety and - # allow the adjustNeighbor computation to be based on keyboard - # state as well as attribute flags. - # - # TODO implement this properly (or just rewrite this entire - # control, because like everything else in Wx, it's crap). - event.m_shiftDown = True - return super(wxSplitter, self)._OnMouse(event) - - def _GetWindowMin(self, window): - """ Overriden parent class method which properly computes the - window min size. - - """ - size = window.GetEffectiveMinSize() - if self._orient == wx.HORIZONTAL: - res = size.GetWidth() - else: - res = size.GetHeight() - return res - - def _GetSashSize(self): - """ Overridden parent class method to return a proper sash size - for the custom sash painting. - - """ - return 4 - - def _DrawSash(self, dc): - """ Overridden parent class method which draws a custom sash. - - On Windows, the default themed sash drawing causes the sash to - not be visible; this method corrects that problem and draws a - sash which is visibly similar to Enaml's Qt Windows version. - - """ - sash_size = self._GetSashSize() - width, height = self.GetClientSize() - light_pen = wx.WHITE_PEN - dark_pen = wx.GREY_PEN - brush = wx.Brush(self.GetBackgroundColour()) - if self._orient == wx.HORIZONTAL: - pos = 0 - for sash in self._sashes[:-1]: - pos += sash - dc.SetPen(wx.TRANSPARENT_PEN) - dc.SetBrush(brush) - dc.DrawRectangle(pos, 0, sash_size, height) - dc.SetPen(light_pen) - dc.DrawLine(pos + 1, 0, pos + 1, height) - dc.SetPen(dark_pen) - dc.DrawLine(pos + 2, 0, pos + 2, height) - pos += sash_size - else: - pos = 0 - for sash in self._sashes[:-1]: - pos += sash - dc.SetPen(wx.TRANSPARENT_PEN) - dc.SetBrush(brush) - dc.DrawRectangle(0, pos, width, sash_size) - dc.SetPen(light_pen) - dc.DrawLine(0, pos + 1, width, pos + 1) - dc.SetPen(dark_pen) - dc.DrawLine(0, pos + 2, width, pos + 2) - pos += sash_size - - def _OnSize(self, event): - """ Overridden parent class method which resizes the sashes. - - The default Wx behavior allocates all extra space to the last - split item, and it will clip the items when the window size is - reduced. This override uses a weighted algorithm to allocate - the free space among the items and will not allow the items - to be clipped by a window resize. - - """ - # Pre-fetch some commonly used objects - get_min = self._GetWindowMin - windows = self._windows - sashes = self._sashes - - # Compute the total space available for the sashes - sash_widths = self._GetSashSize() * (len(windows) - 1) - offset = sash_widths + 2 * self._GetBorderSize() - if self._orient == wx.HORIZONTAL: - free_space = self.GetClientSize().GetWidth() - offset - else: - free_space = self.GetClientSize().GetHeight() - offset - - # Compute the effective stretch factors for each window. The - # effective stretch factor is the greater of the current or - # minimum width of the window, multiplied by the window's - # stretch factor. - parts = [] - total_stretch = 0 - for idx, (sash, window) in enumerate(zip(sashes, windows)): - minw = get_min(window) - if sash < minw: - sash = sashes[idx] = minw - stretch = window.GetStretch() * sash - parts.append((stretch, idx, minw, window)) - total_stretch += stretch - - # Add (or remove) the extra space by fairly allocating it to - # each window based on their effective stretch factor. - diff_space = free_space - sum(sashes) - for stretch, idx, minw, window in parts: - if stretch > 0: - d = diff_space * stretch / total_stretch - new = max(sashes[idx] + d, minw) - sashes[idx] = new - - # Since the windows are clipped to their minimum width, it's - # possible that the current space occupied by the windows will - # be too large. In that case, the overage is distributed to the - # windows fairly, based on their relative capacity for shrink. - curr_space = sum(sashes) - if curr_space > free_space: - diffs = [] - total_diff = 0 - for stretch, idx, minw, window in parts: - diff = sashes[idx] - minw - if diff > 0: - diffs.append((diff, window, idx, minw)) - total_diff += diff - remaining = curr_space - free_space - diffs.sort() - for diff, window, idx, minw in reversed(diffs): - delta = remaining * diff / total_diff - old = sashes[idx] - new = max(old - delta, minw) - actual_diff = old - new - remaining -= actual_diff - total_diff -= actual_diff - sashes[idx] = new - - # The superclass handler which will actually perform the layout. - super(wxSplitter, self)._OnSize(event) - - -class WxSplitter(WxConstraintsWidget, ProxySplitter): - """ A Wx implementation of an Enaml ProxySplitter. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxSplitter) - - #-------------------------------------------------------------------------- - # Setup methods - #-------------------------------------------------------------------------- - def create_widget(self): - """ Creates the underlying wxSplitter widget. - - """ - self.widget = wxSplitter(self.parent_widget()) - - def init_widget(self): - """ Initialize the underlying control. - - """ - super(WxSplitter, self).init_widget() - d = self.declaration - self.set_orientation(d.orientation) - self.set_live_drag(d.live_drag) - - def init_layout(self): - """ Handle the layout initialization for the splitter. - - """ - super(WxSplitter, self).init_layout() - widget = self.widget - for item in self.split_items(): - widget.AppendWindow(item) - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def child_added(self, child): - """ Handle the child added event for a WxSplitter. - - """ - super(WxSplitter, self).child_added(child) - if isinstance(child, WxSplitItem): - for index, dchild in enumerate(self.children()): - if child is dchild: - self.widget.InsertWindow(index, child.widget) - self.geometry_updated() - - def child_removed(self, child): - """ Handle the child removed event for a WxSplitter. - - """ - super(WxSplitter, self).child_removed(child) - if isinstance(child, WxSplitItem): - widget = child.widget - self.widget.DetachWindow(widget) - widget.Hide() - self.geometry_updated() - - #-------------------------------------------------------------------------- - # Utility Methods - #-------------------------------------------------------------------------- - def split_items(self): - """ Get the split items defined for the widget. - - """ - for d in self.declaration.split_items(): - yield d.proxy.widget or None - - #-------------------------------------------------------------------------- - # ProxySplitter API - #-------------------------------------------------------------------------- - def set_orientation(self, orientation): - """ Update the orientation of the splitter. - - """ - wx_orientation = _ORIENTATION_MAP[orientation] - widget = self.widget - with self.geometry_guard(): - widget.SetOrientation(wx_orientation) - widget.SizeWindows() - - def set_live_drag(self, live_drag): - """ Updates the drag state of the splitter. - - """ - if live_drag: - self.widget.WindowStyle |= wx.SP_LIVE_UPDATE - else: - self.widget.WindowStyle &= ~wx.SP_LIVE_UPDATE diff --git a/enaml/wx/wx_tool_bar.py b/enaml/wx/wx_tool_bar.py deleted file mode 100644 index 7aceca891..000000000 --- a/enaml/wx/wx_tool_bar.py +++ /dev/null @@ -1,463 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.tool_bar import ProxyToolBar - -from .wx_action import WxAction, EVT_ACTION_CHANGED -from .wx_action_group import WxActionGroup -from .wx_constraints_widget import WxConstraintsWidget - - -#: A mapping from Enaml orientation to wx Orientation -_ORIENTATION_MAP = { - 'horizontal': wx.HORIZONTAL, - 'vertical': wx.VERTICAL, -} - - -class wxToolBar(wx.ToolBar): - """ A wx.ToolBar subclass which handles wxAction instances. - - """ - def __init__(self, *args, **kwargs): - """ Initialize a wxToolBar. - - Parameters - ---------- - *args, **kwargs - The position and keyword arguments needed to initialize - an AuiToolBar. - - """ - super(wxToolBar, self).__init__(*args, **kwargs) - self._all_items = [] - self._actions_map = {} - - #-------------------------------------------------------------------------- - # Private API - #-------------------------------------------------------------------------- - def _InsertAction(self, index, action): - """ Insert a new tool into the tool bar for the given action. - - Parameters - ---------- - action : wxAction - The wxAction instance to add to the tool bar. - - Returns - ------- - result : wxToolBarToolBase - The tool base item created when adding the control to the - tool bar. - - """ - if action.IsSeparator(): - item = self.InsertSeparator(index) - else: - text = action.GetText() - short_help = action.GetToolTip() - long_help = action.GetStatusTip() - action_id = action.GetId() - bmp = wx.EmptyBitmap(0, 0) - if action.IsCheckable(): - item = self.InsertLabelTool( - index, action_id, text, bmp, kind=wx.ITEM_CHECK, - shortHelp=short_help, longHelp=long_help, - ) - if action.IsChecked() != item.IsToggled(): - item.Toggle() - else: - item = self.InsertLabelTool( - index, action_id, text, bmp, kind=wx.ITEM_NORMAL, - shortHelp=short_help, longHelp=long_help, - ) - item.Enable(action.IsEnabled()) - return item - - def OnActionChanged(self, event): - """ The event handler for the EVT_ACTION_CHANGED event. - - This handler will be called when a child action changes. It - ensures that the new state of the child action is in sync with - the associated tool bar item. - - """ - event.Skip() - action = event.GetEventObject() - item = self._actions_map.get(action) - - # Handle a visibility change. The tool must be added/removed. - visible = action.IsVisible() - if visible != bool(item): - if visible: - index = self._all_items.index(action) - index = min(index, len(self._actions_map)) - new_item = self._InsertAction(index, action) - self._actions_map[action] = new_item - self.Realize() - else: - self.DeleteTool(item.GetId()) - del self._actions_map[action] - return - - # If the item is invisible, there is nothing to update. - if not item: - return - - # Handle a separator change. The existing tool must be replaced. - if action.IsSeparator() != item.IsSeparator(): - self.DeleteTool(item.GetId()) - del self._actions_map[action] - index = self._all_items.index(action) - index = min(index, len(self._actions_map)) - new_item = self._InsertAction(index, action) - self._actions_map[action] = new_item - self.Realize() - return - - # Handle a checkable change. The existing too must be replaced. - if action.IsCheckable() != item.CanBeToggled(): - self.DeleteTool(item.GetId()) - del self._actions_map[action] - index = self._all_items.index(action) - index = min(index, len(self._actions_map)) - new_item = self._InsertAction(index, action) - self._actions_map[action] = new_item - self.Realize() - return - - # All other state can be updated in-place. - item.SetLabel(action.GetText()) - item.SetShortHelp(action.GetToolTip()) - item.SetLongHelp(action.GetStatusTip()) - if action.IsCheckable(): - if action.IsChecked() != item.IsToggled(): - item.Toggle() - item.Enable(action.IsEnabled()) - self.Realize() - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def AddAction(self, action, realize=True): - """ Add an action to the tool bar. - - If the action already exists in the toolbar, it will be moved - to the end. - - Parameters - ---------- - action : wxAction - The wxAction instance to add to the tool bar. - - realize : bool, optional - Whether the toolbar should realize the change immediately. - If False, Realize() will need to be called manually once - all desired changes have been made. The default is True. - - """ - self.InsertAction(None, action, realize) - - def AddActions(self, actions, realize=True): - """ Add multiple wx actions to the tool bar. - - If an action already exists in the tool bar, it will be moved - to the end. - - Parameters - ---------- - actions : iterable - An iterable of wxAction instances to add to the tool bar. - - realize : bool, optional - Whether the toolbar should realize the change immediately. - If False, Realize() will need to be called manually once - all desired changes have been made. The default is True. - - """ - insert = self.InsertAction - for action in actions: - insert(None, action, False) - if realize: - self.Realize() - - def InsertAction(self, before, action, realize=True): - """ Insert a wx action into the tool bar. - - If the action already exists in the tool bar, it will be moved - to the proper location. - - Parameters - ---------- - before : wxAction or None - The action in the tool bar which should come directly after - the new action. - - action : wxAction - The wxAction instance to insert into this tool bar. - - realize : bool, optional - Whether the toolbar should realize the change immediately. - If False, Realize() will need to be called manually once - all desired changes have been made. The default is True. - - """ - all_items = self._all_items - if action not in all_items: - if before in all_items: - index = all_items.index(before) - else: - index = len(all_items) - all_items.insert(index, action) - if action.IsVisible(): - max_index = len(self._actions_map) - index = min(index, max_index) - item = self._InsertAction(index, action) - self._actions_map[action] = item - action.Bind(EVT_ACTION_CHANGED, self.OnActionChanged) - if realize: - self.Realize() - else: - # XXX this is a potentially slow way to do things if the - # number of actions being moved around is large. But, the - # Wx apis don't appear to offer a better way, so this is - # what we get (as usual...). - self.RemoveAction(action) - self.InsertAction(before, action, realize) - - def InsertActions(self, before, actions, realize=True): - """ Insert multiple wx actions into the Menu. - - If an action already exists in this menu, it will be moved to - the proper location. - - Parameters - ---------- - before : wxAction, wxMenu, or None - The item in the menu which should come directly after the - new actions. - - actions : iterable - An iterable of wxAction instances to add to the tool bar. - - realize : bool, optional - Whether the toolbar should realize the change immediately. - If False, Realize() will need to be called manually once - all desired changes have been made. The default is True. - - """ - insert = self.InsertAction - for action in actions: - insert(before, action, False) - if realize: - self.Realize() - - def RemoveAction(self, action): - """ Remove a wx action from the tool bar. - - If the action does not exist in the tool bar, this is a no-op. - - Parameters - ---------- - action : wxAction - The wxAction instance to remove from this tool bar. - - """ - all_items = self._all_items - if action in all_items: - all_items.remove(action) - action.Unbind(EVT_ACTION_CHANGED, handler=self.OnActionChanged) - item = self._actions_map.pop(action, None) - if item is not None: - self.DeleteTool(item.GetId()) - - def RemoveActions(self, actions): - """ Remove multiple actions from the tool bar. - - If an action does not exist in the tool bar, it will be ignored. - - Parameters - ---------- - actions : iterable - An iterable of wxActions to remove from the tool bar. - - """ - remove = self.RemoveAction - for action in actions: - remove(action) - - -class WxToolBar(WxConstraintsWidget, ProxyToolBar): - """ A Wx implementation of an Enaml ToolBar. - - """ - #: A reference to the widget created by the proxy. - widget = Typed(wxToolBar) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the QCustomToolBar widget. - - """ - # The orientation of a tool bar can only be set at creation time. - # Wx does not support changing it dynamically. It is only set if - # the tool bar is a child of something other than a wx.Frame. - # The style must include TB_FLAT or separators won't be drawn. - d = self.declaration - parent = self.parent_widget() - style = wx.TB_FLAT | wx.TB_TEXT | wx.NO_BORDER - if not isinstance(parent, wx.Frame): - style |= _ORIENTATION_MAP[d.orientation] - else: - style |= wx.HORIZONTAL - - self.widget = wxToolBar(parent, style=style) - - # Setting the tool bar to double buffered avoids a ton of - # flickering on Windows during resize events. - self.widget.SetDoubleBuffered(True) - - # For now, we set the bitmap size to 0 since we don't yet - # support icons or images. - self.widget.SetToolBitmapSize(wx.Size(0, 0)) - - def init_layout(self): - """ Initialize the layout for the toolbar. - - """ - super(WxToolBar, self).init_layout() - widget = self.widget - for child in self.children(): - if isinstance(child, WxAction): - widget.AddAction(child.widget, False) - elif isinstance(child, WxActionGroup): - widget.AddActions(child.actions(), False) - widget.Realize() - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def find_next_action(self, child): - """ Locate the wxAction object which logically follows the child. - - Parameters - ---------- - child : WxToolkitObject - The child object of interest. - - Returns - ------- - result : wxAction or None - The wxAction which logically follows the position of the - child in the list of children. None will be returned if - a relevant wxAction is not found. - - """ - found = False - for dchild in self.children(): - if found: - if isinstance(dchild, WxAction): - return dchild.widget - if isinstance(dchild, WxActionGroup): - acts = dchild.actions() - if len(acts) > 0: - return acts[0] - else: - found = dchild is child - - def child_added(self, child): - """ Handle the child added event for a WxToolBar. - - """ - super(WxToolBar, self).child_added(child) - if isinstance(child, WxAction): - before = self.find_next_action(child) - self.widget.InsertAction(before, child.widget) - elif isinstance(child, WxActionGroup): - before = self.find_next_action(child) - self.widget.InsertActions(before, child.actions()) - - def child_removed(self, child): - """ Handle the child removed event for a WxToolBar. - - """ - super(WxToolBar, self).child_removed(child) - if isinstance(child, WxAction): - if child.widget is not None: - self.widget.RemoveAction(child.widget) - elif isinstance(child, WxActionGroup): - self.widget.RemoveActions(child.actions()) - - #-------------------------------------------------------------------------- - # ProxyToolBar API - #-------------------------------------------------------------------------- - def set_visible(self, visible): - """ Overridden parent class visibility setter which properly - handles the visibility of the tool bar. - - """ - # XXX implement me! - pass - - def set_button_style(self, style): - """ This is not supported on wx. - - """ - pass - - def set_orientation(self, orientation): - """ Set the orientation of the underlying widget. - - """ - # Wx does not support dynamically changing the orientation. - pass - - def set_movable(self, movable): - """ Set the movable state on the underlying widget. - - """ - # The standard wx toolbar doesn't support docking. The Aui - # toolbar sucks, don't use it. - pass - - def set_floatable(self, floatable): - """ Set the floatable state on the underlying widget. - - """ - # The standard wx toolbar doesn't support docking. The Aui - # toolbar sucks, don't use it. - pass - - def set_floating(self, floating): - """ Set the floating staet on the underlying widget. - - """ - # The standard wx toolbar doesn't support docking. The Aui - # toolbar sucks, don't use it. - pass - - def set_dock_area(self, dock_area): - """ Set the dock area on the underyling widget. - - """ - # The standard wx toolbar doesn't support docking. The Aui - # toolbar sucks, don't use it. - pass - - def set_allowed_dock_areas(self, dock_areas): - """ Set the allowed dock areas on the underlying widget. - - """ - # The standard wx toolbar doesn't support docking. The Aui - # toolbar sucks, don't use it. - pass diff --git a/enaml/wx/wx_toolkit_object.py b/enaml/wx/wx_toolkit_object.py deleted file mode 100644 index ace9fb9f5..000000000 --- a/enaml/wx/wx_toolkit_object.py +++ /dev/null @@ -1,114 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.toolkit_object import ProxyToolkitObject - - -class WxToolkitObject(ProxyToolkitObject): - """ A Wx implementation of an Enaml ProxyToolkitObject. - - """ - #: A reference to the toolkit widget created by the proxy. - widget = Typed(wx.Object) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Create the toolkit widget for the proxy object. - - This method is called during the top-down pass, just before the - 'init_widget()' method is called. This method should create the - toolkit widget and assign it to the 'widget' attribute. - - """ - self.widget = wx.Object() - - def init_widget(self): - """ Initialize the state of the toolkit widget. - - This method is called during the top-down pass, just after the - 'create_widget()' method is called. This method should init the - state of the widget. The child widgets will not yet be created. - - """ - pass - - def init_layout(self): - """ Initialize the layout of the toolkit widget. - - This method is called during the bottom-up pass. This method - should initialize the layout of the widget. The child widgets - will be fully initialized and layed out when this is called. - - """ - pass - - #-------------------------------------------------------------------------- - # ProxyToolkitObject API - #-------------------------------------------------------------------------- - def activate_top_down(self): - """ Activate the proxy tree for the top-down pass. - - """ - self.create_widget() - self.init_widget() - - def activate_bottom_up(self): - """ Activate the proxy tree for the bottom-up pass. - - """ - self.init_layout() - - def destroy(self): - """ A reimplemented destructor. - - This destructor will drop the reference to the toolkit widget. - - """ - if self.widget: - try: - self.widget.Destroy() - except AttributeError: - pass - del self.widget - super(WxToolkitObject, self).destroy() - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def parent_widget(self): - """ Get the parent toolkit widget for this object. - - Returns - ------- - result : wxObject or None - The toolkit widget declared on the declaration parent, or - None if there is no such parent. - - """ - parent = self.parent() - if parent is not None: - if parent.widget: - return parent.widget - - def child_widgets(self): - """ Get the child toolkit widgets for this object. - - Returns - ------- - result : iterable of wxObject - The child widgets defined for this object. - - """ - for child in self.children(): - if child.widget: - yield child.widget diff --git a/enaml/wx/wx_upstream/__init__.py b/enaml/wx/wx_upstream/__init__.py deleted file mode 100644 index 0bc6ead48..000000000 --- a/enaml/wx/wx_upstream/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ diff --git a/enaml/wx/wx_upstream/aui/__init__.py b/enaml/wx/wx_upstream/aui/__init__.py deleted file mode 100644 index 6c9cc46f3..000000000 --- a/enaml/wx/wx_upstream/aui/__init__.py +++ /dev/null @@ -1,298 +0,0 @@ -""" -AUI is an Advanced User Interface library that aims to implement "cutting-edge" -interface usability and design features so developers can quickly and easily create -beautiful and usable application interfaces. - - -Vision and Design Principles -============================ - -AUI attempts to encapsulate the following aspects of the user interface: - -* **Frame Management**: Frame management provides the means to open, move and hide common - controls that are needed to interact with the document, and allow these configurations - to be saved into different perspectives and loaded at a later time. - -* **Toolbars**: Toolbars are a specialized subset of the frame management system and should - behave similarly to other docked components. However, they also require additional - functionality, such as "spring-loaded" rebar support, "chevron" buttons and end-user - customizability. - -* **Modeless Controls**: Modeless controls expose a tool palette or set of options that - float above the application content while allowing it to be accessed. Usually accessed - by the toolbar, these controls disappear when an option is selected, but may also be - "torn off" the toolbar into a floating frame of their own. - -* **Look and Feel**: Look and feel encompasses the way controls are drawn, both when shown - statically as well as when they are being moved. This aspect of user interface design - incorporates "special effects" such as transparent window dragging as well as frame animation. - -AUI adheres to the following principles: - -- Use native floating frames to obtain a native look and feel for all platforms; -- Use existing wxPython code where possible, such as sizer implementation for frame management; -- Use standard wxPython coding conventions. - - -Usage -===== - -The following example shows a simple implementation that uses :class:`framemanager.AuiManager` to manage -three text controls in a frame window:: - - import wx - import wx.lib.agw.aui as aui - - class MyFrame(wx.Frame): - - def __init__(self, parent, id=-1, title="AUI Test", pos=wx.DefaultPosition, - size=(800, 600), style=wx.DEFAULT_FRAME_STYLE): - - wx.Frame.__init__(self, parent, id, title, pos, size, style) - - self._mgr = aui.AuiManager() - - # notify AUI which frame to use - self._mgr.SetManagedWindow(self) - - # create several text controls - text1 = wx.TextCtrl(self, -1, "Pane 1 - sample text", - wx.DefaultPosition, wx.Size(200,150), - wx.NO_BORDER | wx.TE_MULTILINE) - - text2 = wx.TextCtrl(self, -1, "Pane 2 - sample text", - wx.DefaultPosition, wx.Size(200,150), - wx.NO_BORDER | wx.TE_MULTILINE) - - text3 = wx.TextCtrl(self, -1, "Main content window", - wx.DefaultPosition, wx.Size(200,150), - wx.NO_BORDER | wx.TE_MULTILINE) - - # add the panes to the manager - self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One")) - self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two")) - self._mgr.AddPane(text3, AuiPaneInfo().CenterPane()) - - # tell the manager to "commit" all the changes just made - self._mgr.Update() - - self.Bind(wx.EVT_CLOSE, self.OnClose) - - - def OnClose(self, event): - - # deinitialize the frame manager - self._mgr.UnInit() - - self.Destroy() - event.Skip() - - - # our normal wxApp-derived class, as usual - - app = wx.App(0) - - frame = MyFrame(None) - app.SetTopWindow(frame) - frame.Show() - - app.MainLoop() - - -What's New -========== - -Current wxAUI Version Tracked: wxWidgets 2.9.4 (SVN HEAD) - -The wxPython AUI version fixes the following bugs or implement the following -missing features (the list is not exhaustive): - -- Visual Studio 2005 style docking: http://www.kirix.com/forums/viewtopic.php?f=16&t=596 -- Dock and Pane Resizing: http://www.kirix.com/forums/viewtopic.php?f=16&t=582 -- Patch concerning dock resizing: http://www.kirix.com/forums/viewtopic.php?f=16&t=610 -- Patch to effect wxAuiToolBar orientation switch: http://www.kirix.com/forums/viewtopic.php?f=16&t=641 -- AUI: Core dump when loading a perspective in wxGTK (MSW OK): http://www.kirix.com/forums/viewtopic.php?f=15&t=627 -- wxAuiNotebook reordered AdvanceSelection(): http://www.kirix.com/forums/viewtopic.php?f=16&t=617 -- Vertical Toolbar Docking Issue: http://www.kirix.com/forums/viewtopic.php?f=16&t=181 -- Patch to show the resize hint on mouse-down in aui: http://trac.wxwidgets.org/ticket/9612 -- The Left/Right and Top/Bottom Docks over draw each other: http://trac.wxwidgets.org/ticket/3516 -- MinSize() not honoured: http://trac.wxwidgets.org/ticket/3562 -- Layout problem with wxAUI: http://trac.wxwidgets.org/ticket/3597 -- Resizing children ignores current window size: http://trac.wxwidgets.org/ticket/3908 -- Resizing panes under Vista does not repaint background: http://trac.wxwidgets.org/ticket/4325 -- Resize sash resizes in response to click: http://trac.wxwidgets.org/ticket/4547 -- "Illegal" resizing of the AuiPane? (wxPython): http://trac.wxwidgets.org/ticket/4599 -- Floating wxAUIPane Resize Event doesn't update its position: http://trac.wxwidgets.org/ticket/9773 -- Don't hide floating panels when we maximize some other panel: http://trac.wxwidgets.org/ticket/4066 -- wxAUINotebook incorrect ALLOW_ACTIVE_PANE handling: http://trac.wxwidgets.org/ticket/4361 -- Page changing veto doesn't work, (patch supplied): http://trac.wxwidgets.org/ticket/4518 -- Show and DoShow are mixed around in wxAuiMDIChildFrame: http://trac.wxwidgets.org/ticket/4567 -- wxAuiManager & wxToolBar - ToolBar Of Size Zero: http://trac.wxwidgets.org/ticket/9724 -- wxAuiNotebook doesn't behave properly like a container as far as...: http://trac.wxwidgets.org/ticket/9911 -- Serious layout bugs in wxAUI: http://trac.wxwidgets.org/ticket/10620 -- wAuiDefaultTabArt::Clone() should just use copy contructor: http://trac.wxwidgets.org/ticket/11388 -- Drop down button for check tool on wxAuiToolbar: http://trac.wxwidgets.org/ticket/11139 - -Plus the following features: - -- AuiManager: - - (a) Implementation of a simple minimize pane system: Clicking on this minimize button causes a new - AuiToolBar to be created and added to the frame manager, (currently the implementation is such - that panes at West will have a toolbar at the right, panes at South will have toolbars at the - bottom etc...) and the pane is hidden in the manager. - Clicking on the restore button on the newly created toolbar will result in the toolbar being - removed and the original pane being restored; - (b) Panes can be docked on top of each other to form `AuiNotebooks`; `AuiNotebooks` tabs can be torn - off to create floating panes; - (c) On Windows XP, use the nice sash drawing provided by XP while dragging the sash; - (d) Possibility to set an icon on docked panes; - (e) Possibility to draw a sash visual grip, for enhanced visualization of sashes; - (f) Implementation of a native docking art (`ModernDockArt`). Windows XP only, **requires** Mark Hammond's - pywin32 package (winxptheme); - (g) Possibility to set a transparency for floating panes (a la Paint .NET); - (h) Snapping the main frame to the screen in any positin specified by horizontal and vertical - alignments; - (i) Snapping floating panes on left/right/top/bottom or any combination of directions, a la Winamp; - (j) "Fly-out" floating panes, i.e. panes which show themselves only when the mouse hover them; - (k) Ability to set custom bitmaps for pane buttons (close, maximize, etc...); - (l) Implementation of the style ``AUI_MGR_ANIMATE_FRAMES``, which fade-out floating panes when - they are closed (all platforms which support frames transparency) and show a moving rectangle - when they are docked and minimized (Windows < Vista and GTK only); - (m) A pane switcher dialog is available to cycle through existing AUI panes; - (n) Some flags which allow to choose the orientation and the position of the minimized panes; - (o) The functions [Get]MinimizeMode() in `AuiPaneInfo` which allow to set/get the flags described above; - (p) Events like ``EVT_AUI_PANE_DOCKING``, ``EVT_AUI_PANE_DOCKED``, ``EVT_AUI_PANE_FLOATING`` and ``EVT_AUI_PANE_FLOATED`` are - available for all panes *except* toolbar panes; - (q) Implementation of the RequestUserAttention method for panes; - (r) Ability to show the caption bar of docked panes on the left instead of on the top (with caption - text rotated by 90 degrees then). This is similar to what `wxDockIt` did. To enable this feature on any - given pane, simply call `CaptionVisible(True, left=True)`; - (s) New Aero-style docking guides: you can enable them by using the `AuiManager` style ``AUI_MGR_AERO_DOCKING_GUIDES``; - (t) A slide-in/slide-out preview of minimized panes can be seen by enabling the `AuiManager` style - ``AUI_MGR_PREVIEW_MINIMIZED_PANES`` and by hovering with the mouse on the minimized pane toolbar tool; - (u) New Whidbey-style docking guides: you can enable them by using the `AuiManager` style ``AUI_MGR_WHIDBEY_DOCKING_GUIDES``; - (v) Native of custom-drawn mini frames can be used as floating panes, depending on the ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style; - (w) A "smooth docking effect" can be obtained by using the ``AUI_MGR_SMOOTH_DOCKING`` style (similar to PyQT docking style); - (x) Implementation of "Movable" panes, i.e. a pane that is set as `Movable()` but not `Floatable()` can be dragged and docked - into a new location but will not form a floating window in between. - - -- AuiNotebook: - - (a) Implementation of the style ``AUI_NB_HIDE_ON_SINGLE_TAB``, a la :mod:`lib.agw.flatnotebook`; - (b) Implementation of the style ``AUI_NB_SMART_TABS``, a la :mod:`lib.agw.flatnotebook`; - (c) Implementation of the style ``AUI_NB_USE_IMAGES_DROPDOWN``, which allows to show tab images - on the tab dropdown menu instead of bare check menu items (a la :mod:`lib.agw.flatnotebook`); - (d) 6 different tab arts are available, namely: - - (1) Default "glossy" theme (as in :class:`~auibook.AuiNotebook`) - (2) Simple theme (as in :class:`~auibook.AuiNotebook`) - (3) Firefox 2 theme - (4) Visual Studio 2003 theme (VC71) - (5) Visual Studio 2005 theme (VC81) - (6) Google Chrome theme - - (e) Enabling/disabling tabs; - (f) Setting the colour of the tab's text; - (g) Implementation of the style ``AUI_NB_CLOSE_ON_TAB_LEFT``, which draws the tab close button on - the left instead of on the right (a la Camino browser); - (h) Ability to save and load perspectives in `AuiNotebook` (experimental); - (i) Possibility to add custom buttons in the `AuiNotebook` tab area; - (j) Implementation of the style ``AUI_NB_TAB_FLOAT``, which allows the floating of single tabs. - Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far - enough outside of the notebook to become floating pages; - (k) Implementation of the style ``AUI_NB_DRAW_DND_TAB`` (on by default), which draws an image - representation of a tab while dragging; - (l) Implementation of the `AuiNotebook` unsplit functionality, which unsplit a splitted AuiNotebook - when double-clicking on a sash; - (m) Possibility to hide all the tabs by calling `HideAllTAbs`; - (n) wxPython controls can now be added inside page tabs by calling `AddControlToPage`, and they can be - removed by calling `RemoveControlFromPage`; - (o) Possibility to preview all the pages in a `AuiNotebook` (as thumbnails) by using the `NotebookPreview` - method of `AuiNotebook`; - (p) Tab labels can be edited by calling the `SetRenamable` method on a `AuiNotebook` page; - (q) Support for multi-lines tab labels in `AuiNotebook`; - (r) Support for setting minimum and maximum tab widths for fixed width tabs; - (s) Implementation of the style ``AUI_NB_ORDER_BY_ACCESS``, which orders the tabs by last access time - inside the Tab Navigator dialog; - (t) Implementation of the style ``AUI_NB_NO_TAB_FOCUS``, allowing the developer not to draw the tab - focus rectangle on tne `AuiNotebook` tabs. - -| - -- AuiToolBar: - - (a) ``AUI_TB_PLAIN_BACKGROUND`` style that allows to easy setup a plain background to the AUI toolbar, - without the need to override drawing methods. This style contrasts with the default behaviour - of the :class:`~auibar.AuiToolBar` that draws a background gradient and this break the window design when - putting it within a control that has margin between the borders and the toolbar (example: put - :class:`~auibar.AuiToolBar` within a :class:`StaticBoxSizer` that has a plain background); - (b) `AuiToolBar` allow item alignment: http://trac.wxwidgets.org/ticket/10174; - (c) `AUIToolBar` `DrawButton()` improvement: http://trac.wxwidgets.org/ticket/10303; - (d) `AuiToolBar` automatically assign new id for tools: http://trac.wxwidgets.org/ticket/10173; - (e) `AuiToolBar` Allow right-click on any kind of button: http://trac.wxwidgets.org/ticket/10079; - (f) `AuiToolBar` idle update only when visible: http://trac.wxwidgets.org/ticket/10075; - (g) Ability of creating `AuiToolBar` tools with [counter]clockwise rotation. This allows to propose a - variant of the minimizing functionality with a rotated button which keeps the caption of the pane - as label; - (h) Allow setting the alignment of all tools in a toolbar that is expanded; - (i) Implementation of the ``AUI_MINIMIZE_POS_TOOLBAR`` flag, which allows to minimize a pane inside - an existing toolbar. Limitation: if the minimized icon in the toolbar ends up in the overflowing - items (i.e., a menu is needed to show the icon), this style will not work. - - - -TODOs -===== - -- Documentation, documentation and documentation; -- Fix `tabmdi.AuiMDIParentFrame` and friends, they do not work correctly at present; -- Allow specification of `CaptionLeft()` to `AuiPaneInfo` to show the caption bar of docked panes - on the left instead of on the top (with caption text rotated by 90 degrees then). This is - similar to what `wxDockIt` did - DONE; -- Make developer-created `AuiNotebooks` and automatic (framemanager-created) `AuiNotebooks` behave - the same way (undocking of tabs) - DONE, to some extent; -- Find a way to dock panes in already floating panes (`AuiFloatingFrames`), as they already have - their own `AuiManager`; -- Add more gripper styles (see, i.e., PlusDock 4.0); -- Add an "AutoHide" feature to docked panes, similar to fly-out floating panes (see, i.e., PlusDock 4.0); -- Add events for panes when they are about to float or to be docked (something like - ``EVT_AUI_PANE_FLOATING/ED`` and ``EVT_AUI_PANE_DOCKING/ED``) - DONE, to some extent; -- Implement the 4-ways splitter behaviour for horizontal and vertical sashes if they intersect; -- Extend `tabart.py` with more aui tab arts; -- Implement ``AUI_NB_LEFT`` and ``AUI_NB_RIGHT`` tab locations in `AuiNotebook`; -- Move `AuiDefaultToolBarArt` into a separate module (as with `tabart.py` and `dockart.py`) and - provide more arts for toolbars (maybe from :mod:`lib.agw.flatmenu`?) -- Support multiple-rows/multiple columns toolbars; -- Integrate as much as possible with :mod:`lib.agw.flatmenu`, from dropdown menus in `AuiNotebook` to - toolbars and menu positioning; -- Possibly handle minimization of panes in a different way (or provide an option to switch to - another way of minimizing panes); -- Clean up/speed up the code, especially time-consuming for-loops; -- Possibly integrate `wxPyRibbon` (still on development), at least on Windows. - - -License And Version -=================== - -AUI library is distributed under the wxPython license. - -Latest Revision: Andrea Gavana @ 25 Apr 2012, 21.00 GMT - -Version 1.3. - -""" - -__author__ = "Andrea Gavana " -__date__ = "31 March 2009" - - -from aui_constants import * -from aui_utilities import * -from auibar import * -from auibook import * -from tabart import * -from dockart import * -from framemanager import * -from tabmdi import * diff --git a/enaml/wx/wx_upstream/aui/aui_constants.py b/enaml/wx/wx_upstream/aui/aui_constants.py deleted file mode 100644 index e07caba48..000000000 --- a/enaml/wx/wx_upstream/aui/aui_constants.py +++ /dev/null @@ -1,2594 +0,0 @@ -""" -This module contains all the constants used by wxPython-AUI. - -Especially important and meaningful are constants for AuiManager, AuiDockArt and -AuiNotebook. -""" - -__author__ = "Andrea Gavana " -__date__ = "31 March 2009" - - -import wx -from wx.lib.embeddedimage import PyEmbeddedImage - -# ------------------------- # -# - AuiNotebook Constants - # -# ------------------------- # - -# For tabart -# -------------- - -vertical_border_padding = 4 -""" Border padding used in drawing tabs. """ - -if wx.Platform == "__WXMAC__": - nb_close_bits = "\xFF\xFF\xFF\xFF\x0F\xFE\x03\xF8\x01\xF0\x19\xF3" \ - "\xB8\xE3\xF0\xE1\xE0\xE0\xF0\xE1\xB8\xE3\x19\xF3" \ - "\x01\xF0\x03\xF8\x0F\xFE\xFF\xFF" - """ AuiNotebook close button image on wxMAC. """ - -elif wx.Platform == "__WXGTK__": - nb_close_bits = "\xff\xff\xff\xff\x07\xf0\xfb\xef\xdb\xed\x8b\xe8" \ - "\x1b\xec\x3b\xee\x1b\xec\x8b\xe8\xdb\xed\xfb\xef" \ - "\x07\xf0\xff\xff\xff\xff\xff\xff" - """ AuiNotebook close button image on wxGTK. """ - -else: - nb_close_bits = "\xff\xff\xff\xff\xff\xff\xff\xff\xe7\xf3\xcf\xf9" \ - "\x9f\xfc\x3f\xfe\x3f\xfe\x9f\xfc\xcf\xf9\xe7\xf3" \ - "\xff\xff\xff\xff\xff\xff\xff\xff" - """ AuiNotebook close button image on wxMSW. """ - -nb_left_bits = "\xff\xff\xff\xff\xff\xff\xff\xfe\x7f\xfe\x3f\xfe\x1f" \ - "\xfe\x0f\xfe\x1f\xfe\x3f\xfe\x7f\xfe\xff\xfe\xff\xff" \ - "\xff\xff\xff\xff\xff\xff" -""" AuiNotebook left button image. """ - -nb_right_bits = "\xff\xff\xff\xff\xff\xff\xdf\xff\x9f\xff\x1f\xff\x1f" \ - "\xfe\x1f\xfc\x1f\xfe\x1f\xff\x9f\xff\xdf\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff" -""" AuiNotebook right button image. """ - -nb_list_bits = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x0f" \ - "\xf8\xff\xff\x0f\xf8\x1f\xfc\x3f\xfe\x7f\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff" -""" AuiNotebook windows list button image. """ - - -#---------------------------------------------------------------------- -tab_active_center = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAbCAYAAAC9WOV0AAAABHNCSVQICAgIfAhkiAAAADNJ" - "REFUCJltzMEJwDAUw9DHX6OLdP/Bop4KDc3F2EIYrsFtrZow8GnH6OD1zvRTajvY2QMHIhNx" - "jUhuAgAAAABJRU5ErkJggg==") -""" Center active tab image for the Chrome tab art. """ - -#---------------------------------------------------------------------- -tab_active_left = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAbCAYAAACjkdXHAAAABHNCSVQICAgIfAhkiAAAAglJ" - "REFUOI2Nkk9rE0EYh5/J7mpW06xE2iSmeFHxEoqIAc/FQ5CKgn4DP4KlIQG/QVsQbBEKgop+" - "Anvy4rV4bLT2JCGJPVXqwaZJd+f1kN26WTfJDrzszDLPPL/5o0jeFGAC54A0YKmEYAo4DzjA" - "LHAZmElqtIGrhmEsvtzcfPNtb6/V6524SWALKBiGsfhxe/uzFhGth5XEmgVubWxsvA1Az68k" - "1nngYbPZ7ASg69c06wxwe3V9/b3reVqHwGmwCZRs2370fX//wIuA0+CLwEKj0XilZTSu602G" - "FcP7vLe7+7XlRaCgPw62gGv5fP6p63raiwFdLWKOgdNArl6vV1UqpQgcYdcYbwooAPfb7c7h" - "mTWmUjGwCWTL5fL1K6VSLiqQyMTYyLVa/UEwe9IC0chFYKnb/XnkeiIDV+Q0UsG/qNkCnEql" - "crNQLDpaxpskJnYayD1bXl4S/xrDoPLHKjQOmsHwlCuHv44+ZJ2sLTrGGqzg7zEc+VK1Wl1w" - "HMcG0DFxw6sFsRVwAZhdWak9FoRJ+w2HCKzzwN3jXv+daVmGDkdWoMKb9fumHz0DFFfX1p5Y" - "lmXo6N0G48jzVEDOt97pdA9ezOXzGU+PzBmN6VuDqyoDN3Z2vjyfKxQynhYkJuJ/L02Ara3X" - "n3602r8HrpaTUy3HAy1/+hNq8O+r+q4WETirmFMNBwm3v+gdmytKNIUpAAAAAElFTkSuQmCC") -""" Left active tab image for the Chrome tab art. """ - -#---------------------------------------------------------------------- -tab_active_right = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAbCAYAAACjkdXHAAAABHNCSVQICAgIfAhkiAAAAkpJ" - "REFUOI2NlM1rU0EUxX9zZ5KaWq3GKKnGutC0FEWCWAWLRUOxBetK/wdp6Re6F6TFXXGhuFdw" - "b7dCQUUpiFt1XbB2q7Uf1iTvunjzkpe0afNgmLnDnHvOPe/OWCALtAFC+Cktfha4CRwBDnhg" - "BQhaSrK19bf89dv35WfPX7y01haBbiAFmH3BlUA1Gm8WFt75BFkg0TK4VAl0Y3NL5+efvgIK" - "wOH92EVjxRljGBi4VgTOeLDbk7kcqEZju1TWX7/Xgtm5J6+BS8ChvdilLhAhkUya4eFbxVQq" - "1e3ZbUtgg8GKJd/Tk70/NjYCHCPsgX1kV8K5VA70z8amfvy0tAwMAcebSRfijikY8ez5/OlM" - "JrOncbIjp4K1lmRb0sw8eDgCpAm7rwlz46YIzjpGb48WveyDNPhDfCOuHmNwzpHL5dK9fX3n" - "mkmvaxJiayOCWMvM1PSdZtJrhiloLJMYIeESDFwf7Acyu0mXGLYmX0PpYi3ZbFdnoVDoBTpp" - "uCxCjFob1tYKzlnGJyZHd5Mu6uVGkqvMCmCwzjE4eOMqcALoINauUic37hjhLXPWcTSdThWL" - "QxcJX5yqdGk4H/cP9a4755iYnLpL+M/b8e0qjafrekb9TUskuNx/5TzQ5Y1zO9yOZEd1R7OI" - "JdXebh/Pzt3zCToAMZv/AjU1orDWWKAGVJVSqcTqysp6X+/ZaeAL8KNac9wsVQ8yNeOsdZw8" - "let4/2HpEdAPXDAb20HLj7xqeHT158ra4uLbz2bdg03krmetxrH9KDAmHP8Bn0j1t/01UV0A" - "AAAASUVORK5CYII=") -""" Right active tab image for the Chrome tab art. """ - -#---------------------------------------------------------------------- -tab_close = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABHNCSVQICAgIfAhkiAAAAI9J" - "REFUKJG90MEKAWEUxfEfM4rxAFIommzZzNb7v4BsLJTsiGQlYjHfME3flrO75/xvnXv5p/qY" - "R/wcWTUktWCKFbrYB6/AAhecmwunAI/RwQAjbLGpoFakwjLATxzqMLQjC68A3/FohkljLkKN" - "Ha4YKg8+VkBag3Pll9a1GikmuPk+4qMMs0jFMXoR/0d6A9JRFV/jxY+iAAAAAElFTkSuQmCC") -""" Normal close button image for the Chrome tab art. """ - -#---------------------------------------------------------------------- -tab_close_h = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABHNCSVQICAgIfAhkiAAAAOlJ" - "REFUKJGVkiFuw0AQRd849hUS7iPUwGEllhyjYJ+gaK9Q4CsY9QTFIY4shQQucI8Q7l6h3Z0S" - "r7UgjdrPZvVm52k0wpJLWe4y51qgVpECQFQnYPzabN4ra2cAAbgWxZMmyavAkTtROIn33fM0" - "fcilLHep92+/wXHTd5K8JJlzbYD3w8C2aVZo2zTsh4FF5Zg516ZAHYBb35MbszbkxnDr+3hQ" - "napIIUv1eT6vYPggvAGoSJE88r6XVFQnRA7BOdYIk8IUUZ1SYAQOsXOskRsT1+P/11pZO4v3" - "ncLpESzed5W1c1jQn0/jBzPfck1qdmfjAAAAAElFTkSuQmCC") -""" Hover close button image for the Chrome tab art. """ - -#---------------------------------------------------------------------- -tab_close_p = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABHNCSVQICAgIfAhkiAAAASxJ" - "REFUKJF9kbFLQlEYxX/nvbs55OAkiJAE7k7Nibo9xf+hrTlyr3Boipb+BCGq0bApJEQcG0Ms" - "aQ0Lmq5+Dc+nDtbZ7uHce37fd8VSlWwh50PfRKqClWJXI8y6bu5uHj5e3wEEcJDP75txLBSx" - "RYbdS7QfJ5PnsJIt5BbB4hQjkrQtjxlFILOXyvQDH/qmUCSJznDAYetkFTxsndAZDggkhCIf" - "+qaLmWP1bu8oN+qrC+VGnd7t3bpKqrp4wBjl+ux8FUweSLwlXCnYCv2PHGgE1BLmTYykad2i" - "kcOsi1TbZN7EKDfq67NZV5VsIeedvzQjCv5YK8R/4bw7Cl+/P7920+kJkBEq/hWWaPem45cQ" - "YDybTfdSmf5CizckwHaAH9ATZldu7i560/ELwC+6RXdU6KzezAAAAABJRU5ErkJggg==") -""" Pressed close button image for the Chrome tab art. """ - -#---------------------------------------------------------------------- -tab_inactive_center = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAbCAYAAAC9WOV0AAAABHNCSVQICAgIfAhkiAAAAElJ" - "REFUCJlVyiEOgDAUBNHp3qmX5iYkyMpqBAaFILRdDGn4qybZB98yy3ZZrRu1PpABAQiDSLN+" - "h4NLEU8CBAfoPHZUywr3M/wCTz8c3/qQrUcAAAAASUVORK5CYII=") -""" Center inactive tab image for the Chrome tab art. """ - -#---------------------------------------------------------------------- -tab_inactive_left = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAbCAYAAACjkdXHAAAABHNCSVQICAgIfAhkiAAAAf5J" - "REFUOI2llE1rE1EUhp8bZwyhaZomk5DaD40hSWPQVkTd6KIIEUWlLqTEhTaLulBQ6sfKjeBC" - "ECULXQku/Alx7d6/U1EQae45LjJpJ5NOnOKBgYG5z33Px3sG/iPMIc87QAmYBZKHgdOu69a2" - "3/W2yrVGK5vPLTlxFV3Xrb3+8v1Ntd5oiSpWBmnEidKT972tar3R6ovSt4qoxoIdoFipNlpW" - "B6AVRYFEHNWn3a8dz/PK1rIHEgN2UpnMseVTK7fUGBME48CFe88+3sh5+SXr1xmMSbABvJXz" - "l9siYAVGWJ0Mu/OVZr5Q8CpWfFWzD2Imj2qu/fhtG4wRVUIZg0bDBsgtn15dt6qIKKBDQZ81" - "kWmnzly6OZ+ZzhSt7jfK6CBjFMwEk5TWOy82AVQGhzVUb5RJEkC2fLK6JgIiPhioeZJJUhev" - "3j2RTqdzooqge2ojCxwxqrnrG4/uq4Ida3HgAjMOJ4CZSq1+RVBUzCgQinDDstfa282jyeTU" - "rhUGF4CJgMPKhbXbmw9VFfG7fBA4LCao7AAzi8cXz1kF0dENMqH38KgWnnd7nSMJxxE5wI4+" - "MHyCaeeAYvPshQ0RJby3wVSDHxxgAVh99elb9/evndmfP3boW2FsqGNhMMCdBy8/fJ5KZ6at" - "qL+3Q1dEzFkNGMX82ZWh18e0/vVT/wuFmdYVv/ruKgAAAABJRU5ErkJggg==") -""" Left inactive tab image for the Chrome tab art. """ - -#---------------------------------------------------------------------- -tab_inactive_right = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAbCAYAAACjkdXHAAAABHNCSVQICAgIfAhkiAAAAhBJ" - "REFUOI2llM9rE1EQxz8zb1dSTKNuYtW01kQDRoKFWi9FEEq1IooUUWoPokWCtVqkR69KsSBU" - "8OJRPOhBxZNe/At6FBER/HFUPEq1IGn3ecgm2ZjdJODCHPY9vvP9fufNDPzHZ4DDQBrYBKwB" - "ftfoJys/Kw9ef/1y8/6rh67rHgKS3WLl6cqqtcCGD58+vn+zdPXorUql8g5Y7wTWdd+y4Vus" - "teQK+yfKi8/KwM5umBXAAgioCIP54gTQBzgdwTbsQZR0JpOfXXw+0w27hn9EBGMcyRcPnulJ" - "pbKd2JvACKgKnpcePH99+TSwvT3YEphusKsqB4ZHp4FMNWUn5loSEVSFbZ63b8eeUhpwu5Md" - "JBFRjHHk7LXb08CuNuAaZTgEEaFQHJoEvDjpakOYmnURUFWSvam+0ujJfqAnmlnABhG2jlTZ" - "j19YuEzMm7dUu34hihrDQG7vGLCViPq0VruuvdquyWSvN3xsKhclvbXaoUQiihFlfLJ8iYiq" - "O/EtUC2xGGF3vjAObAnI6stCsZbYCLwnEonNY+dulALvHWSH2YN2PXLq4hz/9HpjnmOs18DZ" - "bP9IIL0+afV5juqzRgLFcV1n9u6LGWAgWnaMBFHBOIbi0MgU1S3jAcjyyw9xqpvzWou1Pj++" - "f/t8b/7EAvBW5u48agU37abWs99rv1YfL81fkT8V34YxbZ696d4CfwEszZSZx6Z26wAAAABJ" - "RU5ErkJggg==") -""" Right inactive tab image for the Chrome tab art. """ - -# For auibook -# ----------- - -AuiBaseTabCtrlId = 5380 -""" Base window identifier for AuiTabCtrl. """ - -AUI_NB_TOP = 1 << 0 -""" With this style, tabs are drawn along the top of the notebook. """ -AUI_NB_LEFT = 1 << 1 # not implemented yet -""" With this style, tabs are drawn along the left of the notebook. -Not implemented yet. """ -AUI_NB_RIGHT = 1 << 2 # not implemented yet -""" With this style, tabs are drawn along the right of the notebook. -Not implemented yet. """ -AUI_NB_BOTTOM = 1 << 3 -""" With this style, tabs are drawn along the bottom of the notebook. """ -AUI_NB_TAB_SPLIT = 1 << 4 -""" Allows the tab control to be split by dragging a tab. """ -AUI_NB_TAB_MOVE = 1 << 5 -""" Allows a tab to be moved horizontally by dragging. """ -AUI_NB_TAB_EXTERNAL_MOVE = 1 << 6 -""" Allows a tab to be moved to another tab control. """ -AUI_NB_TAB_FIXED_WIDTH = 1 << 7 -""" With this style, all tabs have the same width. """ -AUI_NB_SCROLL_BUTTONS = 1 << 8 -""" With this style, left and right scroll buttons are displayed. """ -AUI_NB_WINDOWLIST_BUTTON = 1 << 9 -""" With this style, a drop-down list of windows is available. """ -AUI_NB_CLOSE_BUTTON = 1 << 10 -""" With this style, a close button is available on the tab bar. """ -AUI_NB_CLOSE_ON_ACTIVE_TAB = 1 << 11 -""" With this style, a close button is available on the active tab. """ -AUI_NB_CLOSE_ON_ALL_TABS = 1 << 12 -""" With this style, a close button is available on all tabs. """ -AUI_NB_MIDDLE_CLICK_CLOSE = 1 << 13 -""" Allows to close `AuiNotebook` tabs by mouse middle button click. """ -AUI_NB_SUB_NOTEBOOK = 1 << 14 -""" This style is used by `AuiManager` to create automatic `AuiNotebooks`. """ -AUI_NB_HIDE_ON_SINGLE_TAB = 1 << 15 -""" Hides the tab window if only one tab is present. """ -AUI_NB_SMART_TABS = 1 << 16 -""" Use `Smart Tabbing`, like ``Alt`` + ``Tab`` on Windows. """ -AUI_NB_USE_IMAGES_DROPDOWN = 1 << 17 -""" Uses images on dropdown window list menu instead of check items. """ -AUI_NB_CLOSE_ON_TAB_LEFT = 1 << 18 -""" Draws the tab close button on the left instead of on the right -(a la Camino browser). """ -AUI_NB_TAB_FLOAT = 1 << 19 -""" Allows the floating of single tabs. -Known limitation: when the notebook is more or less full screen, tabs -cannot be dragged far enough outside of the notebook to become -floating pages. """ -AUI_NB_DRAW_DND_TAB = 1 << 20 -""" Draws an image representation of a tab while dragging. """ -AUI_NB_ORDER_BY_ACCESS = 1 << 21 -""" Tab navigation order by last access time. """ -AUI_NB_NO_TAB_FOCUS = 1 << 22 -""" Don't draw tab focus rectangle. """ - -AUI_NB_DEFAULT_STYLE = AUI_NB_TOP | AUI_NB_TAB_SPLIT | AUI_NB_TAB_MOVE | \ - AUI_NB_SCROLL_BUTTONS | AUI_NB_CLOSE_ON_ACTIVE_TAB | \ - AUI_NB_MIDDLE_CLICK_CLOSE | AUI_NB_DRAW_DND_TAB -""" Default `AuiNotebook` style. """ - -#---------------------------------------------------------------------- -Mondrian = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAHFJ" - "REFUWIXt1jsKgDAQRdF7xY25cpcWC60kioI6Fm/ahHBCMh+BRmGMnAgEWnvPpzK8dvrFCCCA" - "coD8og4c5Lr6WB3Q3l1TBwLYPuF3YS1gn1HphgEEEABcKERrGy0E3B0HFJg7C1N/f/kTBBBA" - "+Vi+AMkgFEvBPD17AAAAAElFTkSuQmCC") -""" Default icon for the Smart Tabbing dialog. """ - -# -------------------------- # -# - FrameManager Constants - # -# -------------------------- # - -# Docking Styles -AUI_DOCK_NONE = 0 -""" No docking direction. """ -AUI_DOCK_TOP = 1 -""" Top docking direction. """ -AUI_DOCK_RIGHT = 2 -""" Right docking direction. """ -AUI_DOCK_BOTTOM = 3 -""" Bottom docking direction. """ -AUI_DOCK_LEFT = 4 -""" Left docking direction. """ -AUI_DOCK_CENTER = 5 -""" Center docking direction. """ -AUI_DOCK_CENTRE = AUI_DOCK_CENTER -""" Centre docking direction. """ -AUI_DOCK_NOTEBOOK_PAGE = 6 -""" Automatic AuiNotebooks docking style. """ - -# Floating/Dragging Styles -AUI_MGR_ALLOW_FLOATING = 1 << 0 -""" Allow floating of panes. """ -AUI_MGR_ALLOW_ACTIVE_PANE = 1 << 1 -""" If a pane becomes active, "highlight" it in the interface. """ -AUI_MGR_TRANSPARENT_DRAG = 1 << 2 -""" If the platform supports it, set transparency on a floating pane -while it is dragged by the user. """ -AUI_MGR_TRANSPARENT_HINT = 1 << 3 -""" If the platform supports it, show a transparent hint window when -the user is about to dock a floating pane. """ -AUI_MGR_VENETIAN_BLINDS_HINT = 1 << 4 -""" Show a "venetian blind" effect when the user is about to dock a -floating pane. """ -AUI_MGR_RECTANGLE_HINT = 1 << 5 -""" Show a rectangle hint effect when the user is about to dock a -floating pane. """ -AUI_MGR_HINT_FADE = 1 << 6 -""" If the platform supports it, the hint window will fade in and out. """ -AUI_MGR_NO_VENETIAN_BLINDS_FADE = 1 << 7 -""" Disables the "venetian blind" fade in and out. """ -AUI_MGR_LIVE_RESIZE = 1 << 8 -""" Live resize when the user drag a sash. """ -AUI_MGR_ANIMATE_FRAMES = 1 << 9 -""" Fade-out floating panes when they are closed (all platforms which support -frames transparency) and show a moving rectangle when they are docked -(Windows < Vista and GTK only). """ -AUI_MGR_AERO_DOCKING_GUIDES = 1 << 10 -""" Use the new Aero-style bitmaps as docking guides. """ -AUI_MGR_PREVIEW_MINIMIZED_PANES = 1 << 11 -""" Slide in and out minimized panes to preview them. """ -AUI_MGR_WHIDBEY_DOCKING_GUIDES = 1 << 12 -""" Use the new Whidbey-style bitmaps as docking guides. """ -AUI_MGR_SMOOTH_DOCKING = 1 << 13 -""" Performs a "smooth" docking of panes (a la PyQT). """ -AUI_MGR_USE_NATIVE_MINIFRAMES = 1 << 14 -""" Use miniframes with native caption bar as floating panes instead or custom -drawn caption bars (forced on wxMac). """ -AUI_MGR_AUTONB_NO_CAPTION = 1 << 15 -""" Panes that merge into an automatic notebook will not have the pane -caption visible. """ - - -AUI_MGR_DEFAULT = AUI_MGR_ALLOW_FLOATING | AUI_MGR_TRANSPARENT_HINT | \ - AUI_MGR_HINT_FADE | AUI_MGR_NO_VENETIAN_BLINDS_FADE -""" Default `AuiManager` style. """ - -# Panes Customization -AUI_DOCKART_SASH_SIZE = 0 -""" Customizes the sash size. """ -AUI_DOCKART_CAPTION_SIZE = 1 -""" Customizes the caption size. """ -AUI_DOCKART_GRIPPER_SIZE = 2 -""" Customizes the gripper size. """ -AUI_DOCKART_PANE_BORDER_SIZE = 3 -""" Customizes the pane border size. """ -AUI_DOCKART_PANE_BUTTON_SIZE = 4 -""" Customizes the pane button size. """ -AUI_DOCKART_BACKGROUND_COLOUR = 5 -""" Customizes the background colour. """ -AUI_DOCKART_BACKGROUND_GRADIENT_COLOUR = 6 -""" Customizes the background gradient colour. """ -AUI_DOCKART_SASH_COLOUR = 7 -""" Customizes the sash colour. """ -AUI_DOCKART_ACTIVE_CAPTION_COLOUR = 8 -""" Customizes the active caption colour. """ -AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR = 9 -""" Customizes the active caption gradient colour. """ -AUI_DOCKART_INACTIVE_CAPTION_COLOUR = 10 -""" Customizes the inactive caption colour. """ -AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR = 11 -""" Customizes the inactive gradient caption colour. """ -AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR = 12 -""" Customizes the active caption text colour. """ -AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR = 13 -""" Customizes the inactive caption text colour. """ -AUI_DOCKART_BORDER_COLOUR = 14 -""" Customizes the border colour. """ -AUI_DOCKART_GRIPPER_COLOUR = 15 -""" Customizes the gripper colour. """ -AUI_DOCKART_CAPTION_FONT = 16 -""" Customizes the caption font. """ -AUI_DOCKART_GRADIENT_TYPE = 17 -""" Customizes the gradient type (no gradient, vertical or horizontal). """ -AUI_DOCKART_DRAW_SASH_GRIP = 18 -""" Draw a sash grip on the sash. """ -AUI_DOCKART_HINT_WINDOW_COLOUR = 19 -""" Customizes the hint window background colour (currently light blue). """ - -# Caption Gradient Type -AUI_GRADIENT_NONE = 0 -""" No gradient on the captions. """ -AUI_GRADIENT_VERTICAL = 1 -""" Vertical gradient on the captions. """ -AUI_GRADIENT_HORIZONTAL = 2 -""" Horizontal gradient on the captions. """ - -# Pane Button State -AUI_BUTTON_STATE_NORMAL = 0 -""" Normal button state. """ -AUI_BUTTON_STATE_HOVER = 1 << 1 -""" Hovered button state. """ -AUI_BUTTON_STATE_PRESSED = 1 << 2 -""" Pressed button state. """ -AUI_BUTTON_STATE_DISABLED = 1 << 3 -""" Disabled button state. """ -AUI_BUTTON_STATE_HIDDEN = 1 << 4 -""" Hidden button state. """ -AUI_BUTTON_STATE_CHECKED = 1 << 5 -""" Checked button state. """ - -# Pane minimize mode -AUI_MINIMIZE_POS_SMART = 0x01 -""" Minimizes the pane on the closest tool bar. """ -AUI_MINIMIZE_POS_TOP = 0x02 -""" Minimizes the pane on the top tool bar. """ -AUI_MINIMIZE_POS_LEFT = 0x03 -""" Minimizes the pane on its left tool bar. """ -AUI_MINIMIZE_POS_RIGHT = 0x04 -""" Minimizes the pane on its right tool bar. """ -AUI_MINIMIZE_POS_BOTTOM = 0x05 -""" Minimizes the pane on its bottom tool bar. """ -AUI_MINIMIZE_POS_TOOLBAR = 0x06 -""" Minimizes the pane on its bottom tool bar. """ -AUI_MINIMIZE_POS_MASK = 0x17 -""" Mask to filter the position flags. """ -AUI_MINIMIZE_CAPT_HIDE = 0 -""" Hides the caption of the minimized pane. """ -AUI_MINIMIZE_CAPT_SMART = 0x08 -""" Displays the caption in the best rotation (horz or clockwise). """ -AUI_MINIMIZE_CAPT_HORZ = 0x10 -""" Displays the caption horizontally. """ -AUI_MINIMIZE_CAPT_MASK = 0x18 -""" Mask to filter the caption flags. """ - -# Button kind -AUI_BUTTON_CLOSE = 101 -""" Shows a close button on the pane. """ -AUI_BUTTON_MAXIMIZE_RESTORE = 102 -""" Shows a maximize/restore button on the pane. """ -AUI_BUTTON_MINIMIZE = 103 -""" Shows a minimize button on the pane. """ -AUI_BUTTON_PIN = 104 -""" Shows a pin button on the pane. """ -AUI_BUTTON_OPTIONS = 105 -""" Shows an option button on the pane (not implemented). """ -AUI_BUTTON_WINDOWLIST = 106 -""" Shows a window list button on the pane (for AuiNotebook). """ -AUI_BUTTON_LEFT = 107 -""" Shows a left button on the pane (for AuiNotebook). """ -AUI_BUTTON_RIGHT = 108 -""" Shows a right button on the pane (for AuiNotebook). """ -AUI_BUTTON_UP = 109 -""" Shows an up button on the pane (not implemented). """ -AUI_BUTTON_DOWN = 110 -""" Shows a down button on the pane (not implemented). """ -AUI_BUTTON_CUSTOM1 = 201 -""" Shows a custom button on the pane. """ -AUI_BUTTON_CUSTOM2 = 202 -""" Shows a custom button on the pane. """ -AUI_BUTTON_CUSTOM3 = 203 -""" Shows a custom button on the pane. """ -AUI_BUTTON_CUSTOM4 = 204 -""" Shows a custom button on the pane. """ -AUI_BUTTON_CUSTOM5 = 205 -""" Shows a custom button on the pane. """ -AUI_BUTTON_CUSTOM6 = 206 -""" Shows a custom button on the pane. """ -AUI_BUTTON_CUSTOM7 = 207 -""" Shows a custom button on the pane. """ -AUI_BUTTON_CUSTOM8 = 208 -""" Shows a custom button on the pane. """ -AUI_BUTTON_CUSTOM9 = 209 -""" Shows a custom button on the pane. """ - -# Pane Insert Level -AUI_INSERT_PANE = 0 -""" Level for inserting a pane. """ -AUI_INSERT_ROW = 1 -""" Level for inserting a row. """ -AUI_INSERT_DOCK = 2 -""" Level for inserting a dock. """ - -# Action constants -actionNone = 0 -""" No current action. """ -actionResize = 1 -""" Resize action. """ -actionClickButton = 2 -""" Click on a pane button action. """ -actionClickCaption = 3 -""" Click on a pane caption action. """ -actionDragToolbarPane = 4 -""" Drag a floating toolbar action. """ -actionDragFloatingPane = 5 -""" Drag a floating pane action. """ -actionDragMovablePane = 6 -""" Move a pane action. """ - -# Drop/Float constants -auiInsertRowPixels = 10 -""" Number of pixels between rows. """ -auiNewRowPixels = 40 -""" Number of pixels for a new inserted row. """ -auiLayerInsertPixels = 40 -""" Number of pixels between layers. """ -auiLayerInsertOffset = 5 -""" Number of offset pixels between layers. """ -auiToolBarLayer = 10 -""" AUI layer for a toolbar. """ - -# some built in bitmaps - -if wx.Platform == "__WXMAC__": - - close_bits = "\xFF\xFF\xFF\xFF\x0F\xFE\x03\xF8\x01\xF0\x19\xF3\xB8\xE3\xF0" \ - "\xE1\xE0\xE0\xF0\xE1\xB8\xE3\x19\xF3\x01\xF0\x03\xF8\x0F\xFE\xFF\xFF" - """ Close button bitmap for a pane on wxMAC. """ - -elif wx.Platform == "__WXGTK__": - - close_bits = "\xff\xff\xff\xff\x07\xf0\xfb\xef\xdb\xed\x8b\xe8\x1b\xec\x3b\xee" \ - "\x1b\xec\x8b\xe8\xdb\xed\xfb\xef\x07\xf0\xff\xff\xff\xff\xff\xff" - """ Close button bitmap for a pane on wxGTK. """ - -else: - - close_bits = "\xff\xff\xff\xff\xff\xff\xff\xff\xcf\xf3\x9f\xf9\x3f\xfc\x7f\xfe" \ - "\x3f\xfc\x9f\xf9\xcf\xf3\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" - """ Close button bitmap for a pane on wxMSW. """ - -pin_bits = '\xff\xff\xff\xff\xff\xff\x1f\xfc\xdf\xfc\xdf\xfc\xdf\xfc\xdf\xfc' \ - '\xdf\xfc\x0f\xf8\x7f\xff\x7f\xff\x7f\xff\xff\xff\xff\xff\xff\xff' -""" Pin button bitmap for a pane. """ - -max_bits = '\xff\xff\xff\xff\xff\xff\x07\xf0\xf7\xf7\x07\xf0\xf7\xf7\xf7\xf7' \ - '\xf7\xf7\xf7\xf7\xf7\xf7\x07\xf0\xff\xff\xff\xff\xff\xff\xff\xff' -""" Maximize button bitmap for a pane. """ - -restore_bits = '\xff\xff\xff\xff\xff\xff\x1f\xf0\x1f\xf0\xdf\xf7\x07\xf4\x07\xf4' \ - '\xf7\xf5\xf7\xf1\xf7\xfd\xf7\xfd\x07\xfc\xff\xff\xff\xff\xff\xff' -""" Restore/maximize button bitmap for a pane. """ - -minimize_bits = '\xff\xff\xff\xff\xff\xff\x07\xf0\xf7\xf7\x07\xf0\xff\xff\xff\xff' \ - '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' -""" Minimize button bitmap for a pane. """ - -restore_xpm = ["16 15 3 1", - " c None", - ". c #000000", - "+ c #FFFFFF", - " ", - " .......... ", - " .++++++++. ", - " .......... ", - " .++++++++. ", - " ..........+++. ", - " .++++++++.+++. ", - " ..........+++. ", - " .++++++++..... ", - " .++++++++. ", - " .++++++++. ", - " .++++++++. ", - " .++++++++. ", - " .......... ", - " "] -""" Restore/minimize button bitmap for a pane. """ - -#---------------------------------------------------------------------- - -down_focus_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACaUlE" - "QVRIib2WvWsUQRjGn5mdnWxyTaqz9q+QlLnGToSgWAYDNjbpNCAGDGIvaRPbNJGQyiAEbK+w" - "sAo2qexyEhbxsvt+jMXc3u3liPfhmWeXnWVm9vc+vO/M7prVzTb+gxyA7Ye/nXPWWmvtXKBb" - "B9YBcM5lWZam6by4QNcBsNamaeq9d87NmWutdc59+NgGoKIizCwsxMTMFI8oZmZilzomZiFm" - "FWERaXbv7eyueO+TJEHM79LSkvfeWnv2qftgex2ASGDmkrUkKUspiIuCy5IL4qKQgnghdQVx" - "ScKsxCKiaH8lIu99NOwAEFGsG4Dv5xeiQYOKBBYVUWJlFhIVVmIlEZGQJKVIYBbWoKqqwQN5" - "nqdpuri42OMys6rGOG/X78yW0bXWNyLqcyyAEEIIYcYK3aB5Lazb4o5fsPc3ToFaloxBwMle" - "6+9Pjfd7stda6HR85+dCPC86Y6ETcQEcHz32eZ7meZrnx0ePJnlk0vwenm70r/PkTgWdjjuV" - "rnPPfvxaa+3NcL3GMaub7XdPtNFoZFn24tmX1/trAOLuM6aaFQwQYExAMPWNaUw1FW+eHj5/" - "dbfZbDYajY33F7e1L4gUA5uo3fd8AWbQH70bjGqEyxLq3LoMYhKCgakCIWZoLLdkMRE43Iy0" - "tWi9QOP8xoIFAyBUjF7dgOizb9iMhLmByxIAHbAGKYigUPX3hqog47hSvfCHfYRaDcNg3IzO" - "7GmydRaGi37zMujrut/9l58nijROQ9yd3ZXLy8urq6vZWFmW9f+Yhrje++XlZR2keDpZa4f+" - "H/pKkiR+/f9dDsDWgQW6QHcuxKg/ZbVtCjjzINkAAAAASUVORK5CYII=") -""" VS2005 focused docking guide window down bitmap. """ - -#---------------------------------------------------------------------- -down_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACY0lE" - "QVRIib2WwWrUUBSG/3tzc5s2m0JhXPsU0u1s3Lkpui4W3PgAuhAFi2/QbesTVEphwCIU3Hbh" - "wk2LG1fujJQgtMk55x4Xd2aS6VAzM479JyQhufnOz3/uzcQMBgP8BzkAeZ4756y11tqlQIui" - "cACcc1mWpWm6ZK61Nk1T771zbilcxBxiAs659x/OAAQJIswsLMTEzBR/UczMxC51TMxCzEGE" - "RaR39WB3b9N7nyTJkLu2tua9t9ZefLx69GYbgIgyc82hJqlrqYiriuuaK+Kqkop4JXUVcU3C" - "HIhFJODsCxF57xu/RBT7BuDb958SNGgQUZYgEogDs5AE4UAcSEREk6QWUWbhoCGEENQDZVmm" - "abq6ujrkMnMIIdZ5t31vsUC3+l+JaMyxAFRVVRds0C1azsS6O273hH24cwq0UjIGipP9/t+f" - "6vZ7st9fKQpf/FqJ28+iEzoTF8Dx0RNflmlZpmV5fPR4lkdmzffwdGe8XyZ3Luh83Ll0k3vx" - "4/dWf3+B/Q2OGQwGGxsbeZ5nWfbi2efXB1sA4uozZjRKDaAwRqGmvTCNGQ3F26eHz1/d7/V6" - "eZ6fn5/f1bogCmhsonU+9AWY5nr0bjCtKS6LtrltGcQQ1MCMCiEm1MmtWUwETh6mjq1qw0Jd" - "fmPD1ADQEWPYNyD6HBs2U2Vu4bIoEBpWE0EE6ej68NaoSBdXRi/8SR/a6qE29830yKFmm2c6" - "2fTbp8FYN/0evPw0U6UuTXB39zYvLy+vr68XY2VZNv5imuB679fX10MT8Xyy1k58P4yVJEn8" - "9/93OQBFURRFsRTcWH8An5lwqISXsWUAAAAASUVORK5CYII=") -""" VS2005 unfocused docking guide window down bitmap. """ - -#---------------------------------------------------------------------- -left_focus_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACVElE" - "QVRIibWWvW8TQRDF3+7Ors8ShSsaSpo0dEgoFcINVChSBFRUkajpIKKgiPgP0pqGJiAhITqE" - "FIk2BQUVHT2VK+y7ndmhWN/5Ixcbh8tYWvtO8vvdm5mdPXPv+RmuMgjA670/RGSttdZ2q354" - "YgkAERVF4b3vHABMCIC11nsfQiCiqwJYa4noxbNvOw/6AJIk62ySJMLMwhI5MnPMnxzMzJHJ" - "E0dmicxJhEXk+uTO0fFuCME5h1yDxbh5+zEz93q+LGOv50WUmStOVZSqkjJyWXJVcRm5LKWM" - "3PNURq6iMKfIIpJw9n08Hg8Gg36/3wL4+eu3iHpykcWTS5pElCWJpMiJWaIk4RQ5RRERda4S" - "UWbhpCmllDQA0+k0pZQFVwF3bzEAZ5N3jgje+0COnPVknbUAdm5cW5/1/eGPxcuL2saoAczC" - "DQWAV0/fr1c/HxcBFNC8QGEMMu3NuyddAfIjG9QLjKJTB3NIHV050EZuoQI6+93q4P7B6TYA" - "A2gW1xlC61K0OXi492HZ6EbAnGFqEmBmhlYc7A9HutRq/wgA5plSwDT9tORgfzgCNsmv2QfQ" - "OvEwps7BooOPpwebxFsB83wazdWdl321BjOGWWejrciZ0+wBMwef76LPnx6trXFrivIfVOsl" - "P2V7FwH4MhpuCTBLX7mjckU628naTImlrdDdLDJ59OT+XDDU8SwyTX+Y2bC7hIPVA+fty6/b" - "SmwBODreHY/H0+n0P0WLomjegJYAIYTBYNAcp5cOa20IoQXgnMuvAh0GATg8scAEmHQrneMv" - "3LAo6X/e0vAAAAAASUVORK5CYII=") -""" VS2005 focused docking guide window left bitmap. """ - -#---------------------------------------------------------------------- -left_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACTklE" - "QVRIibWWPWsUURSG3/u5u8RiKxtLmzR2gqQSttFKhKBWqQL+BQXL4D9IGxsrBUGEFCIEbC0s" - "rOzshYHt3Jl7PizuzsduJhs3Ts7C3Z2BfZ95zzn33DGnp6e4zvAAdnZ2vPfWWmvtsOpFUXgA" - "3vvxeBxCuC6AtTaEEGP03g8LQE5RTo73/sXzr7sPJwCExTorLMxExMSJEhGl/MlBRJTIB0+J" - "iBORMBMz3/xz7+h4L8bonFsCunH77lMiGo1CWabRKDArEVUkVeKq4jJRWVJVUZmoLLlMNAq+" - "TFQlJpJEzCz49n0+n0+n08lk0gP4+es3swbvEnHwTlSYlViYJZEQcWJhkkSSmJnVuYpZiZhE" - "RUREI7BYLESkTVE37t8hAM5KcM57hBCid97Z4K2zFsDurRubk74/+9G9vKhtjBrAdG4oALw6" - "eLdZ/XxcBFBA8wKFMci012+fDQXIj2xQLzCKQR20kDqGcqCNXKcCuvzd6+DB4dk2AANoFtcl" - "QutS9Dl49Pj9qtFLAS3D1CTALA2tOdifnehKq/0jAGgzpYBp+mnFwf7sBLhMfsM+gNaJhzF1" - "DroOPpwdXibeC2jzaTRXty37eg2WDLPJRl+RM6fZA6YFn++iTx+fbKxxb4ryH1TrJT9lfxcB" - "+Hwy2xJgVr5yR+WKDLaTtZkSK1thuFlk8ujJ/dkxNPAsMk1/mOWwu4KD9QPnzcsv20psATg6" - "3pvP54vF4j9Fx+Nx8wa0AogxTqfT5ji9clhrY4w9AOdcfhUYMDyAoiiKohhWt4m/9Qss43IB" - "CBMAAAAASUVORK5CYII=") -""" VS2005 unfocused docking guide window left bitmap. """ - -#---------------------------------------------------------------------- -right_focus_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACWElE" - "QVRIibWWv2/TQBTHv3e+uyRbJwZWFv4AJNSRLjChSkhlYqrEzFZVDAwVC3PXsrAUISTExlKJ" - "tQMSWzcmFqaqQqT2+8VwtuMkbiBp+mzF0pPz/dzX7z373IMXp7jJCABebf8JIXjvvffrVd8/" - "9gFACGE4HMYY1w4AxgGA9z7GmFIKIdwUwHsfQth7/vXuoxEAFfWFV1ERZhYWYmJmykcOZmbi" - "EAMTsxCzirCI3BrfPzjcTCkVRYFcg27cubfDzINBLEsaDKKIMXPFWpFUlZTEZclVxSVxWUpJ" - "PIihJK5ImJVYRBSn387Pzzc2NkajUQ/g7McvEYuhIJYYCjUVMRYVUWJlFhIVVmIlERErikrE" - "mIXVVFXVEnB5eamqWXAW8Gb39uKHevbzNwARZVFirUSIlFkqEVUD8Pb71P1Lt83LZ+8BAA7O" - "AYABMAPcFfcvDXj97ikA5wxmHVVrf64LyA7Mau1so770uVjRQa1lzaKtSc2ZWAR4uHsyn2xq" - "YBnjbFp4zsRCBw6Ptz/M5GoHgLla15AfUV8F/gEwA/Bk66jPgXNwMNhkyf199F816DIaB5bx" - "yB2aO2qFLsp/+Xiy22YmczA1Cq4hLQlwsK56xwHgumLWln0pgPv8aWcmNdVF7TKujkWAL0db" - "88nagXWb0xYgVn4XWf0CymdzWQNgapJzWC7HCnPQF5M5aBhXzthqgMkcoF57Zxx6YvaDMzO3" - "148pwMHhJhFdXFwQ0XVEh8NhuwOaAqSUUkoxxvaLulp471NKPYC80ci7gXVFALB/7IExMF6j" - "bht/AXIQRaTUgkiHAAAAAElFTkSuQmCC") -""" VS2005 focused docking guide window right bitmap. """ - -#---------------------------------------------------------------------- -right_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACVElE" - "QVRIibWWv2sUQRTHvzM7M3dHmlQWtjb+AYKkTaOVCEKsrAL+CxaWwcY6bWysRAQRUtgEbC0E" - "u3RWNsJCCILZfb8sZvdu925zej/yveMWHnvvM9837+2OOz09xU0qANjZ2QkheO+999vNXpZl" - "ABBCGI/HMcabAnjvY4wppRDCdgHIJcrFCSG8eP7l7sMJABX1hVdREWYWFmJiZsqfLGZm4hAD" - "E7MQs4qwiNz6c//oeC+lVBRFA+jqzr0DZh6NYlXRaBRFjJlr1pqkrqUiriqua66Iq0oq4lEM" - "FXFNwqzEIqL4+u3i4mJ3d3cymQwAzn/8ErEYCmKJoVBTEWNRESVWZiFRYSVWEhGxoqhFjFlY" - "TVVVLQFXV1eqOitRV68Pby+v6fnP3wBElEWJtRYhUmapRVQNwJvvvftXbpuXz94BABycAwAD" - "YAa4a+5fGfDq7VMAzhnMOllt+rMpIDswa3JnG81lyMWaDppc1i7a2tCCiWWAB4dni8F2Dyxj" - "nPUTL5hY6sDh0eP3c7HGAWCuyWvIJRragX8AzAA82T8ZcuAcHAw2W/JwH/3XHnQZrQPLeOQO" - "zR21Rhflv3w4O5xGZnPQGwXXklYEOFg3e8cB4LrJbLrtKwHcp48Hc6FeF02Xcb2WAT6f7C8G" - "GwfWbU5bglj7WWTNAyh/28sWAL1JzrK8HWvMwZBmc9Ayrp2x9QCzOUCz9s44DGj+hTM3t5ur" - "Bzg63iOiy8tLItok6Xg8np6AeoCUUkopxjh9o64n731KaQCQDxr5NLAtBQBlWZZlucWkXf0F" - "imtJnvbT2psAAAAASUVORK5CYII=") -""" VS2005 unfocused docking guide window right bitmap. """ - -#---------------------------------------------------------------------- -tab_focus_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAIAAADZ8fBYAAAAA3NCSVQICAjb4U/gAAAC10lE" - "QVRIidWWT0gUcRTH387+ZveXZgzsbmvSsmqEfzBJSYz+gUsHCYJgISPytCQKFhJdpIN0qIUO" - "ezIUaU/roQ5eEzp46ZT/DhG4haCXdSUPK+Wuzvze+02HgdFmFqMtD76Bx8yb3/v8vr/3Zn4z" - "np6ReTgCYwAwdqfEGFMURVGU/wIdfaswAGCMcc5VVf1fXIBdBgCKoqiq+nxkobn3BABIkgBA" - "hIiEJFAgorAOyxARBTKVoUAkgSiJkIhO73a/nLjGOd/nWkrPXbqLiH6/CgBEJiIaKA1BhkG6" - "QF1Hw0BdoK6TLtCvMl2gIQhRCiQiCfPLm5ubtbW1YNXXtuzadyJTZV4AkKYkMpEkkRQoEUmQ" - "JJQCpSAiMr1eg8hEJJSmlFJK0wdQLBYR0cl9laj7l6LGY5/tc2ejsrmdgeGJbG5nYHgym9uJ" - "x9KHeGuMNd7B8fSMzCfvyerq6rHHn2bmEgPDE09G+/9WaSqZmRofisfSiadnotHoozclp94K" - "oGWznNxn/e8q4LqznNwXmb4KuO6s4643lZyugOvOcj8PDyrgurOOe30r05tKZv7ALavXmszt" - "rXZZL7EjhTmuU8lpRxNSyemZuUEAmJlLOPzU+CAAuKFluO7OWpF4LO1OPsTcejOOTcRepqXR" - "tngs7Y6U4bbcqNrIF6bGh6yt0prAgm7kC6E2fSNfWF9b2d7e1jStvqGlbMSmeRsuP7zZZvp8" - "PvCoW1s/a2qq7vddD57y3b7VZfmNfGFxadUQBgqztbWps7Pdy04uLq0WSyVJnoMRgUY45NM0" - "bXZZ7OvtaA8vLOdeT85mP+4eXN35K/6W5nBjxFz5tv7+w8LWF3+oTW+IBpsavStf1+xIfTTY" - "cNbknDPGfqsD5/xCa6AuDFe791xtEJyHIhHedTGw17tnj49EeFdH8GAkEAhwzgF+7HMZY5qm" - "cc6tD6rDGGOMMUS075aN2Ho9R/R/9gsXZ7dKHM+ODQAAAABJRU5ErkJggg==") -""" VS2005 focused docking guide window center bitmap. """ - -#---------------------------------------------------------------------- -tab_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAIAAADZ8fBYAAAAA3NCSVQICAjb4U/gAAAC1klE" - "QVRIidWVTWgTQRTHJ5vZZEyMLKSx1RbSImJbioeiCKIechLBU8CCtadAaaGIFC/iQTxowENO" - "hUohp/Tiocdce/Gk/TiIpTm0JCnmA+OaFJs2u/PerIcp27IbKsZ66Ft47P5n3m/evLc768lm" - "s+Q/GCWEBINBSqmiKIqinApU13VKCKGUMsZUVT1lrqIoqqq+frYyeP8cIUSgIIQgAgACcuAA" - "wOUlDQCAA1UpcADkAAIREPHiwa2383cYY0TWwa7AlRuPAMDvVwkhiBYAmCBMjqaJBgfDANME" - "g4NhoMHBr1KDg8kRQHBAREE+r1er1Z6enkOubbn8d0RLpV5CiLAEogUoEAUHAYAcBYLgIDgi" - "ouX1mogWAIKwhBBCWD5Cms0mADi57xKX/6Ws8dgX+97ZqFxpb3JmPlfam5x5nyvtxWPpE7yc" - "I+c7OJ5sNhsOh4PB4Kunn5aWE5Mz87MvJv4201QyszA3HY+lE88vRaPRYrHozLcDaNsoJ/fl" - "xIcOuO4oJ/dNZqwDrjvqrOebSi52wHVHud+HJx1w3VFnvb6d5ZtKZv7AbZuvXMztZbvkR+wI" - "oY7nVHLR0YRUcnFpeYoQsrSccPiFuSlCiBvahuvurFTisbQ7+ARz55txHCL2NmWOtsVjabfS" - "hjt0L1Cu1BfmpuVRKReQ0HKlHhkxypV6Ib/ZaDQ0TesfGGqr2DTv+Ph4IBDw+XzEo9Zqv0Kh" - "wOOxu10XfA8f3JS+XKmvrm2Z3ARuDQ9fGx297qXnV9e2mvv7Aj3HFQ5md8Snadru7u7Rua6q" - "6sp6aTNXzX08OL67q7f9Q4PdTP1ZKCn5Qq321R8ZMQaiXf19VuGbJ1/8IZX+aNdAnxWJRHp7" - "e7e3t4+4oVCo0Wjout5qtdx9YIwxxlqtlj3aVgmHw5qmbWxsHNWXUqppGmNM/lCd/aWUUgoA" - "9mhbhTFGKT3sm67ruq7v7Oy4cR3bb5uW079be13FAAAAAElFTkSuQmCC") -""" VS2005 unfocused docking guide window center bitmap. """ - -#---------------------------------------------------------------------- -up_focus_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACTUlE" - "QVRIic2WP28TMRjGH/85c1miqEF8CnbUgSFdukVRmZGQ+gW6Vgwd+hW60Yq1gMQMQzpHGZAg" - "C6JS+QIMmUju/L5+Ge6ulzoRTcMh5TmdZfv8/vT4Pcu26h2N8R9kAZwMfltrtdZa60agx5fa" - "ArDWpmmaJElTXGBmAWitkyRxzllrG+Zqra21bz+OAQQOzETExJ48EfniKURE5MkmljwRe6LA" - "TMz8ZPbs9GzXOWeMQZHfW33/NOufvALALESUU8g95zlnnrKM8pwyT1nGmadHic085Z6Jgidm" - "Dhh/mU6nnU6n1WrFXAA/fv7iIEECsxAH5uApELHnwBQ8Bc/MLMbkzELEFCSEEII4YD6fhxAK" - "Tsx9/tQDEIgqOzRggAQQQEEBguIFgKoNqDdfvy1yYq41emG4QKkSpDQAiNQfFQClpBoZcaK2" - "s0awEHzXVVyri1gxN7FaFuILu6qwtAyokqWWwEvcxNTTKsIK95Cqs4JJzV02vMJvHS/1cFFQ" - "UGV+K3tSzWlZq/5bOWGllIio0mzpX+pZSJXdVRmOuabcItRC+ZfKcn+pFRvN65fvNihj9Y7G" - "o9FoMplcX18f9M5lUx30zofD4WQyubm56R2Nm9oYY20B98XeRfPcAro+ei1uf/DBt9u+3c7b" - "7f7gfTPc/cOr7HE36+5k3Z28u5N1u/uHV/dG3X+gfb7YW8dgpC1YD1vBjfP7oEW6Lvf0bHc6" - "nc7n881YaZre3pjucJ1znU7n9qx+qLTWzrkVXGNMcav4d1kAx5camAGzRoiF/gCKPmudbgYP" - "HQAAAABJRU5ErkJggg==") -""" VS2005 focused docking guide window up bitmap. """ - -#---------------------------------------------------------------------- -up_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACTklE" - "QVRIic2WP4vUQBjGn/mTMUtgWS6yvb29XGGzzXXHwdWCcGBzH8BCweK+wnWyWKtot6DNge0V" - "gjYnNn4BA9vdJvO+81ok2ewmi7d3RtgnZEgm8/545skwiZrNZvgPsgCSJLHWaq211r1Asyyz" - "AKy1cRxHUdQzV2sdRZFzzlrbCxdlDmUC1to3Hy8BBA7MRMTEnjwR+fIoRUTkyUaWPBF7osBM" - "zDy+fnR2vu+cM8ZU3KV+fLo+fPUUALMQUUGh8FwUnHvKcyoKyj3lOeee7kU291R4JgqemDng" - "8ut8Ph+NRoPBoM0F8PPXbw4SJDALcWAOngIRew5MwVPwzMxiTMEsRExBQgghiAMWi0UIoclh" - "VY8fegACUVWHBgwQAQIoKEBQngBQ3wPq9bfv7XzX7o1eGS5QqgIpDQAizUMFQCmpR3bf26qc" - "NYKV4nVX7aumaavNjayWlfrSriotdQF1WKoD7nAj00yrLCvdQ+rOGiYNt2t4g9+mXprhoqCg" - "qnxre1LPqatN762asFJKRFRltvIvzSykTndTwm2uqbYItdL+5aLbX2nDRvPiyds7tC2p2WyW" - "pmmSJHEcP3/25cPFSXfQNjqeTE9fPhiPx0mSXF1d9bMxdrUD3OPJtH9uCd0evRX38Oi9Hw79" - "cFgMh4dH7/rhHpxc5PfTPN3L070i3cvT9ODk4saqmz9on6eTbQy2tAPrYSe47XxvtUi35Z6d" - "78/n88VicTdWHMfLP6Y1rnNuNBotv9W3ldbaObeBa4wp/yr+XRZAlmVZlvWCW+oP2FUt8NYb" - "g5wAAAAASUVORK5CYII=") -""" VS2005 unfocused docking guide window up bitmap. """ - -#---------------------------------------------------------------------- -down = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACFUlE" - "QVRIidWVPWvbUBSG3+tv8KKpnYtH/4DuJtCti2nntBm7depQWih0zT9w/AtSQsDQ0JIfkKFD" - "wRC61Iu3uBgRiKXz1eFalizb8QfxkFdCurofz3l1zhVyg8EAe1BhH9BHyC3NWkTU/XYFQEVF" - "mFlYiImZyR9ezMzEpXKJiVmIWUVYRJ7cPT/uHizhFgqF6+93Lz8fAhAxZo5ZY5I4log4ijiO" - "OSKOIomIq+VSRByTMCuxiCiufo3H4yAI8txisQjgz98bUVNTEWNRESVWZiFRYSVWEhGxYjEW" - "MWZhNVVVtQoQhuESrtfXw6e7JbTd+k1E6dv3+/3dQPeo3+8/3n22Si+OLgFLn52D4aLTun/V" - "er8XnVZ1NKqM/lX9eTNaC92IC+D87HUlDMthWA7D87NXmyzZNL+nl0ez60Nyt4Jux91Kee71" - "8Lbd6uxwzXFcr9drNpv+4f2bn59O2gDMAMC5ZJY5wOCcwZxlV7tkKr68PX338Vmj0cBev7f8" - "d0GkSG0i0576Alza7707LGqBy2JZblYOPgnm4JJA8Blay41ZnAfO3xbumWjTQOv8+oKZA2AJ" - "Y1o3wPucGXYLYVZwWQzQlJWmwIMs6Z8OJUHWcUU1aWZ9WKaGlo67xZlTbbbPbL7oq7fBTHm/" - "Jx9+bBRpnea4x92D4XA4mUx2Y9VqteVcAEEQ1Ov13bhZ5fP7IFB4v/v41f8HFQ1ap0nfm7YA" - "AAAASUVORK5CYII=") -""" VS2005 unfocused docking guide window down bitmap. """ - -#---------------------------------------------------------------------- -down_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACaUlE" - "QVRIib2WvWsUQRjGn5mdnWxyTaqz9q+QlLnGToSgWAYDNjbpNCAGDGIvaRPbNJGQyiAEbK+w" - "sAo2qexyEhbxsvt+jMXc3u3liPfhmWeXnWVm9vc+vO/M7prVzTb+gxyA7Ye/nXPWWmvtXKBb" - "B9YBcM5lWZam6by4QNcBsNamaeq9d87NmWutdc59+NgGoKIizCwsxMTMFI8oZmZilzomZiFm" - "FWERaXbv7eyueO+TJEHM79LSkvfeWnv2qftgex2ASGDmkrUkKUspiIuCy5IL4qKQgnghdQVx" - "ScKsxCKiaH8lIu99NOwAEFGsG4Dv5xeiQYOKBBYVUWJlFhIVVmIlEZGQJKVIYBbWoKqqwQN5" - "nqdpuri42OMys6rGOG/X78yW0bXWNyLqcyyAEEIIYcYK3aB5Lazb4o5fsPc3ToFaloxBwMle" - "6+9Pjfd7stda6HR85+dCPC86Y6ETcQEcHz32eZ7meZrnx0ePJnlk0vwenm70r/PkTgWdjjuV" - "rnPPfvxaa+3NcL3GMaub7XdPtNFoZFn24tmX1/trAOLuM6aaFQwQYExAMPWNaUw1FW+eHj5/" - "dbfZbDYajY33F7e1L4gUA5uo3fd8AWbQH70bjGqEyxLq3LoMYhKCgakCIWZoLLdkMRE43Iy0" - "tWi9QOP8xoIFAyBUjF7dgOizb9iMhLmByxIAHbAGKYigUPX3hqog47hSvfCHfYRaDcNg3IzO" - "7GmydRaGi37zMujrut/9l58nijROQ9yd3ZXLy8urq6vZWFmW9f+Yhrje++XlZR2keDpZa4f+" - "H/pKkiR+/f9dDsDWgQW6QHcuxKg/ZbVtCjjzINkAAAAASUVORK5CYII=") -""" VS2005 focused docking guide window down bitmap. """ - -#---------------------------------------------------------------------- -left = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACMElE" - "QVRIib2WPYsTURSG3zv3ThKJRSqblDYLwU6wFMKCViIEtbKQ/QdWgrXt/oO4hZWCIEIKUfYH" - "WFgIATuraewHM3PPh8XNZCaTSWI2oydwMx/kfeY959wzMbPZDC3FaDTavOi23Wgron8n/Z8A" - "rnry/NmXk/vXAAhLZCNhYSYiJvbkiciHTwgiIk8uduSJ2BMJMzHzjd93zi9OmwEAbt5+TETd" - "bpxlvtuNmZWIcpLcc55z5inLKM8p85RlnHnqxi7zlHsmEk/MLPj6LUmS4XDYDPjx8xezxs56" - "4thZUWFWYmEWT0LEnoVJPIlnZlZrc2YlYhIVERHtAIvFYquDu7cIgI0kttY5xHHccdbZKHaR" - "jSIAJ8Pru5M+GX+vnm4rslEDmMoFBYCXT9/uVt+MbQAFNCxQGINAe/XmSVuA8MgGxQKjaNVB" - "CSmiLQe6kqtUQJfHjQ7unV0eAjCABnFdIrQoRZODBw/frRvdCygZpiABZmmo5mAynupaq/0l" - "ACgzpYBZ9dOag8l4CuyT37EPoEXiYUyRg6qD95dn+8QbAWU+jYbqlmWv12DJMLtsNBU5cFZ7" - "wJTgzS76+OHRzho3pij8QLVYwlM2dxGAT9PxgQCz9hU6KlSktZ2sqymxthXam0UmjJ7QnxVD" - "Lc8is+oPsxx2V3BQf+G8fvH5UIkDAOcXp0mSVF94V4ter5emab/frwMADAaDcOOYSNO00+mE" - "4zrgePWaiAMwn8+PF932//MPv0Uk8OspzrYAAAAASUVORK5CYII=") -""" VS2005 unfocused docking guide window left bitmap. """ - -#---------------------------------------------------------------------- -left_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACVElE" - "QVRIibWWvW8TQRDF3+7Ors8ShSsaSpo0dEgoFcINVChSBFRUkajpIKKgiPgP0pqGJiAhITqE" - "FIk2BQUVHT2VK+y7ndmhWN/5Ixcbh8tYWvtO8vvdm5mdPXPv+RmuMgjA670/RGSttdZ2q354" - "YgkAERVF4b3vHABMCIC11nsfQiCiqwJYa4noxbNvOw/6AJIk62ySJMLMwhI5MnPMnxzMzJHJ" - "E0dmicxJhEXk+uTO0fFuCME5h1yDxbh5+zEz93q+LGOv50WUmStOVZSqkjJyWXJVcRm5LKWM" - "3PNURq6iMKfIIpJw9n08Hg8Gg36/3wL4+eu3iHpykcWTS5pElCWJpMiJWaIk4RQ5RRERda4S" - "UWbhpCmllDQA0+k0pZQFVwF3bzEAZ5N3jgje+0COnPVknbUAdm5cW5/1/eGPxcuL2saoAczC" - "DQWAV0/fr1c/HxcBFNC8QGEMMu3NuyddAfIjG9QLjKJTB3NIHV050EZuoQI6+93q4P7B6TYA" - "A2gW1xlC61K0OXi492HZ6EbAnGFqEmBmhlYc7A9HutRq/wgA5plSwDT9tORgfzgCNsmv2QfQ" - "OvEwps7BooOPpwebxFsB83wazdWdl321BjOGWWejrciZ0+wBMwef76LPnx6trXFrivIfVOsl" - "P2V7FwH4MhpuCTBLX7mjckU628naTImlrdDdLDJ59OT+XDDU8SwyTX+Y2bC7hIPVA+fty6/b" - "SmwBODreHY/H0+n0P0WLomjegJYAIYTBYNAcp5cOa20IoQXgnMuvAh0GATg8scAEmHQrneMv" - "3LAo6X/e0vAAAAAASUVORK5CYII=") -""" VS2005 focused docking guide window left bitmap. """ - -#---------------------------------------------------------------------- -right = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACMklE" - "QVRIibWWvY7TUBCFz83vojSuKNiShgdAol8hQYWQkJaKAuUNtqWmoeANFgoqhJAQHRLaB6BA" - "orC0HWnSUEURK2LPmRmKayeO4wTysydWbI+c+e7xzDgOo9EIK0rTdDW4m0Ij4FBK07R1fdmj" - "rh3QqZ6cPf965+ENAKbWardMTZWkUoVCUuIniiSFnW6HQqqQpkpVvfnn3uu395sBAG7fPSXZ" - "73ezTPr9rqqTzGm5aJ5rJswy5jkzYZZpJux3O5kwFyVNqKqGb9/H4/Hx8XEz4PLnL1XvdtpC" - "7Xba5qbqVFM1oZEqakoTmqiqerudqzqpNDczM+8Bs9lsrYNXw1ub7+nl+DcAVaOa0HJVESM1" - "VzVzAG9+LF2/dZFfPHsPAAgIAQAcgDsQ1ly/NeDlu6cAQnC4V7L6/GtfQHTgXuSONopdk4sd" - "HRS5vFy0l6EVE5sAD4YXq8GyBh4xwZcTr5jY6CDg0eMPtVjhAPBQ5HXEW9RUgX8A3AE8OTlv" - "chACAhy+WHJzH/1XDaqM0oFHPGKHxo7aoYviTz5eDOeRxRwsjUIoSVsCAryaveIACNVkPi/7" - "VoDw+dNpLbTURfNlrNcmwJfzk9Vg4cCrzekbEDs/i7x4AMWt3B0AsDTJUR7LscMcNGkxByVj" - "7YztBljMAYq1V8ahQfU/nNrc7q/6e9FkMplOpyKyT9Kjo6MkSQaDQZqmdQdJkiRJsk92AFdX" - "V71eLx7XAQfRYDCYH68FHOr19C8Ad0k9S0aHzwAAAABJRU5ErkJggg==") -""" VS2005 unfocused docking guide window right bitmap. """ - -#---------------------------------------------------------------------- -right_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAIAAABE/PnQAAAAA3NCSVQICAjb4U/gAAACWElE" - "QVRIibWWv2/TQBTHv3e+uyRbJwZWFv4AJNSRLjChSkhlYqrEzFZVDAwVC3PXsrAUISTExlKJ" - "tQMSWzcmFqaqQqT2+8VwtuMkbiBp+mzF0pPz/dzX7z373IMXp7jJCABebf8JIXjvvffrVd8/" - "9gFACGE4HMYY1w4AxgGA9z7GmFIKIdwUwHsfQth7/vXuoxEAFfWFV1ERZhYWYmJmykcOZmbi" - "EAMTsxCzirCI3BrfPzjcTCkVRYFcg27cubfDzINBLEsaDKKIMXPFWpFUlZTEZclVxSVxWUpJ" - "PIihJK5ImJVYRBSn387Pzzc2NkajUQ/g7McvEYuhIJYYCjUVMRYVUWJlFhIVVmIlERErikrE" - "mIXVVFXVEnB5eamqWXAW8Gb39uKHevbzNwARZVFirUSIlFkqEVUD8Pb71P1Lt83LZ+8BAA7O" - "AYABMAPcFfcvDXj97ikA5wxmHVVrf64LyA7Mau1so770uVjRQa1lzaKtSc2ZWAR4uHsyn2xq" - "YBnjbFp4zsRCBw6Ptz/M5GoHgLla15AfUV8F/gEwA/Bk66jPgXNwMNhkyf199F816DIaB5bx" - "yB2aO2qFLsp/+Xiy22YmczA1Cq4hLQlwsK56xwHgumLWln0pgPv8aWcmNdVF7TKujkWAL0db" - "88nagXWb0xYgVn4XWf0CymdzWQNgapJzWC7HCnPQF5M5aBhXzthqgMkcoF57Zxx6YvaDMzO3" - "148pwMHhJhFdXFwQ0XVEh8NhuwOaAqSUUkoxxvaLulp471NKPYC80ci7gXVFALB/7IExMF6j" - "bht/AXIQRaTUgkiHAAAAAElFTkSuQmCC") -""" VS2005 focused docking guide window right bitmap. """ - -#---------------------------------------------------------------------- -tab = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAIAAADZ8fBYAAAAA3NCSVQICAjb4U/gAAACq0lE" - "QVRIidWWTWgTQRTHJ+3ETEugERrtF6QhFhKsIlgQRITm5LkBvdiDhBZKc5DiRXryoAEPPRUi" - "pTnVi4cee5NePAitFtFoVxSyheYDa02KCd3deW/Gw2Cy7MZaIz307TK7/Gfeb9587Nvx6LpO" - "TsA6TgJ6glyqHgcHB4/ub0ZvdRFCBApCCCIAICAHDgBcXcoAADhQLwUOgBxAIAIinju89iRz" - "gzHW5Pb09BBCImO3AcDn8xJCECUAWCAsjpaFJgfTBMsCk4NposnB56UmB4sjgOCAiIJsbJXL" - "5b6+PsYYtQev5b8hSi/tJIQIKRAloEAUHAQAchQIgoPgiIiys9NClAAIQgohhJBnCKnX6wDQ" - "jFfZ0+TA/8xpIv6+8e5cN61Qm05ltEJtOvVMK9QS8ewRpWqj2js4nsb+nbv3cnU9OZ3KzD2c" - "/NdIF9IrS4sziXg2+aA/FAr5/X5nvG1AW3o5ufOTL9rgur2c3Mcrd9rgur1Oe7wL6edtcN1e" - "7v1wtw2u2+u0z2978S6kV/7CbRmv6sxdquVSH7HTR/9tE+PLUsqp2cz27k/7PTWbkcezifHl" - "tbW1XC6n6zp1dONeWaUk4tnjTwtx5F81KEcSaQxzdT1p1xPxrFtpwY3d7C6WKkuLMypVqg4U" - "tFiqBEfNYqmi57er1WogEBgOx1oqDVoz/77e2Onu6hq7emGg/6w9imKp8ubt149a/mI0rGqV" - "8u7DlyuXRuzKp8/5yzG/yr9NrmEYm1uFba2svTq0c0eu+2LR88z7Qy905PW9vZwvOGqGQ73D" - "Q1Lf9eR3vitlONQbHpLBYHBwcJAx5rGfd6rV6v7+vmEY7nVgjDHGDMNo1LZUIpGIc34ppYFA" - "gDGmfqgOo5RSSgGgUdtSUSUANLmqWp0q/mTK82hFcX4Bm24GMv+uL+EAAAAASUVORK5CYII=") -""" VS2005 unfocused docking guide window center bitmap. """ - -#---------------------------------------------------------------------- -tab_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAIAAADZ8fBYAAAAA3NCSVQICAjb4U/gAAAC10lE" - "QVRIidWWT0gUcRTH387+ZveXZgzsbmvSsmqEfzBJSYz+gUsHCYJgISPytCQKFhJdpIN0qIUO" - "ezIUaU/roQ5eEzp46ZT/DhG4haCXdSUPK+Wuzvze+02HgdFmFqMtD76Bx8yb3/v8vr/3Zn4z" - "np6ReTgCYwAwdqfEGFMURVGU/wIdfaswAGCMcc5VVf1fXIBdBgCKoqiq+nxkobn3BABIkgBA" - "hIiEJFAgorAOyxARBTKVoUAkgSiJkIhO73a/nLjGOd/nWkrPXbqLiH6/CgBEJiIaKA1BhkG6" - "QF1Hw0BdoK6TLtCvMl2gIQhRCiQiCfPLm5ubtbW1YNXXtuzadyJTZV4AkKYkMpEkkRQoEUmQ" - "JJQCpSAiMr1eg8hEJJSmlFJK0wdQLBYR0cl9laj7l6LGY5/tc2ejsrmdgeGJbG5nYHgym9uJ" - "x9KHeGuMNd7B8fSMzCfvyerq6rHHn2bmEgPDE09G+/9WaSqZmRofisfSiadnotHoozclp94K" - "oGWznNxn/e8q4LqznNwXmb4KuO6s4643lZyugOvOcj8PDyrgurOOe30r05tKZv7ALavXmszt" - "rXZZL7EjhTmuU8lpRxNSyemZuUEAmJlLOPzU+CAAuKFluO7OWpF4LO1OPsTcejOOTcRepqXR" - "tngs7Y6U4bbcqNrIF6bGh6yt0prAgm7kC6E2fSNfWF9b2d7e1jStvqGlbMSmeRsuP7zZZvp8" - "PvCoW1s/a2qq7vddD57y3b7VZfmNfGFxadUQBgqztbWps7Pdy04uLq0WSyVJnoMRgUY45NM0" - "bXZZ7OvtaA8vLOdeT85mP+4eXN35K/6W5nBjxFz5tv7+w8LWF3+oTW+IBpsavStf1+xIfTTY" - "cNbknDPGfqsD5/xCa6AuDFe791xtEJyHIhHedTGw17tnj49EeFdH8GAkEAhwzgF+7HMZY5qm" - "cc6tD6rDGGOMMUS075aN2Ho9R/R/9gsXZ7dKHM+ODQAAAABJRU5ErkJggg==") -""" VS2005 focused docking guide window center bitmap. """ - -#---------------------------------------------------------------------- -up = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACHUlE" - "QVRIidWWP4vUQBjGn8mfcyGQYiM2W8mWsRcLm22uWw6uFpQt7WwVLPwKVsp+gFMsAwqynY2F" - "oLAgNu4HsEiz3E7mfee1yN9Lcueu7oo+IcPMZN4fz7yZzEQlSYIDyAMQx/F+ocvl0tkvsdKh" - "uF6z8eLsAwDLlpmImNiQISKTX7mIiAx5vkeGiA2RZSZmvnF++9nzO0EQ9HC/vj2fPr0PgFmI" - "KCObGc4y1oa0piwjbUhr1oau+Z42lBkmsoaY2eLjpzRN+7kAvn3/wVasWGYhtszWkCViw5bJ" - "GrKGmVlcN2MWIiYr1lpr5QjYbDb9eQBw95YBIBBVdDiAC/iAAAoKEOQ3AJRtQL38/OXS/ALw" - "XKcxXKBUAVIOAIjUDxUApaQcecV7A3DkuYJG8EVX7VpdtNXm+p4jjfjcrsotdQFlslQH3OH6" - "bj2tPCx3Dyk7S5jU3K7hHr91vNTDRUFBFfkt7Uk5p6763lsxYaWUiKjCbOFf6llImd2+DLe5" - "ruM0UlA5uazS7S/Usz88vnf2G2VLKkmSap989OD9m8WsO2gbnU7mD5/cHI/H+C/3yR24p5P5" - "/rk5dHv0VtzpyWsThiYMszCcnrzaD/d4ttDXIx0NdTTMoqGOouPZ4pdR7e+iq3fzyTYGWzrY" - "etj7zwOAOI7/yjmPHRfpFVKr1apqrNfrNE2bx+pOGgwGo9Eor1/wGwRB9QPwh/oH9oed9BPW" - "YyQlBOJt4AAAAABJRU5ErkJggg==") -""" VS2005 unfocused docking guide window up bitmap. """ -#---------------------------------------------------------------------- -up_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB0AAAAgCAIAAABhFeQrAAAAA3NCSVQICAjb4U/gAAACTUlE" - "QVRIic2WP28TMRjGH/85c1miqEF8CnbUgSFdukVRmZGQ+gW6Vgwd+hW60Yq1gMQMQzpHGZAg" - "C6JS+QIMmUju/L5+Ge6ulzoRTcMh5TmdZfv8/vT4Pcu26h2N8R9kAZwMfltrtdZa60agx5fa" - "ArDWpmmaJElTXGBmAWitkyRxzllrG+Zqra21bz+OAQQOzETExJ48EfniKURE5MkmljwRe6LA" - "TMz8ZPbs9GzXOWeMQZHfW33/NOufvALALESUU8g95zlnnrKM8pwyT1nGmadHic085Z6Jgidm" - "Dhh/mU6nnU6n1WrFXAA/fv7iIEECsxAH5uApELHnwBQ8Bc/MLMbkzELEFCSEEII4YD6fhxAK" - "Tsx9/tQDEIgqOzRggAQQQEEBguIFgKoNqDdfvy1yYq41emG4QKkSpDQAiNQfFQClpBoZcaK2" - "s0awEHzXVVyri1gxN7FaFuILu6qwtAyokqWWwEvcxNTTKsIK95Cqs4JJzV02vMJvHS/1cFFQ" - "UGV+K3tSzWlZq/5bOWGllIio0mzpX+pZSJXdVRmOuabcItRC+ZfKcn+pFRvN65fvNihj9Y7G" - "o9FoMplcX18f9M5lUx30zofD4WQyubm56R2Nm9oYY20B98XeRfPcAro+ei1uf/DBt9u+3c7b" - "7f7gfTPc/cOr7HE36+5k3Z28u5N1u/uHV/dG3X+gfb7YW8dgpC1YD1vBjfP7oEW6Lvf0bHc6" - "nc7n881YaZre3pjucJ1znU7n9qx+qLTWzrkVXGNMcav4d1kAx5camAGzRoiF/gCKPmudbgYP" - "HQAAAABJRU5ErkJggg==") -""" VS2005 focused docking guide window up bitmap. """ - -#---------------------------------------------------------------------- -aero_dock_pane = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAMAAABnVw3AAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAb3WKdHqPdnyRd3+deYGge4OifISifoallZaWgIy1g463hZC5hZG6iJO8o6Sk" - "pKSkpKWlpaampqenqKmpqaqqqqurq6ysrKysra6urq+vr7CwsLGxsbKysrOzs7S0tLS0tLW1" - "tba2tre3t7i4uLm5uru7vLy8vL29vr6+iZfLjJrNjpzPjpzQkZ7PkJ/SlKHSkaHek6Pgk6Th" - "labjmKjlnqzhnqzjoa/npbPov8DAwMDAwMHBwsLCwsPDw8TExMXFxsbGycnJycrKysvLzMzM" - "zM3Nzc7Ozs/Pz9DQ0NDQ0NHR0dLS0tPT09TU1NTU1tbW1tfX0tTY19jY1tjd2NjY2dnZ2dra" - "2tvb29zc29zf3Nzc3N3d3d7e3t/fxs7szNPt0NXo0dfu1djk09js2tzk3d/k3d/m2Nzv3N/r" - "1Nr02N713OH13OL23+X43+X54ODg4eHh4eLi4+Pj4uPm4uPn4+Tk5OTk5OXl5ubm5+fn4eLo" - "4uTs5eXp5efv5+jo6Ojo6enp6urq6+vr6Onv7Ozs7O3t7e7u7u/v4Ob55Oj16Ov37e/26+/9" - "7/D28PDw8fHx8vLy8/Pz8/P09PT09fX19vb29vf38vT89ff9+Pj4+Pj5+vr6+vr7+/v8/Pz8" - "/f39/v7+////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAsPpcmgAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAf+SURBVGhD7Zr7d9tEGoa9UKBZCiapneBQN3bUQlgo13DbhXBrnRQnS0LJNhDbUO7s" - "ErCtZWWZm2Rj2YHdbWQsCSQL2/yjZkaypBlpdKH14XA4vL8kkuebx3PR6HtnHBtHkfxyZoGs" - "zMtR4sfjWJRi0mJRHZGlFhej1BCNs1XyocDbpa0ooEjtSfcDOHp6apyFAMzop4XfF2f0K7Vn" - "qpyhr0bT5AwHvhpOkzPQ/TVNjt73lT6c4jzQNV/1p8npq77SBlNsj6b4Sr1Ozmtr99xpvQpm" - "6LKvquyMVezOe9Ze81uDfNbRHLUtiPaqNi8KvrqqztvlRGGbypFJRM7mMoOtnPNHDV8JisOB" - "QczyJolE4qy/MMAX6Pl23VdNGeeMBi+sE0AEzsYl92tgXqj5ipNcnNHo0oYX5OVsnfe8beab" - "VVQcelHveTij895XrJdD6SGc4b+HCIglcHTK0yAPJ4dPAYOJtUd/78b3dAdE4owYz6zzcM4Q" - "3tEop/v18ePHv+7aICJndMbdIDdn93Iwp/vh7VAf2iAy5/KuC+TmPN0J5HQ+eNDUB51Ji8ic" - "zjMhnAwpIbT7TfjXU4+ZeuqfbRNE5miZEE5qGNSe2g//s/RDLYgzSoVwiKlammMmvVTjLE0w" - "NH+UJmV37peFe3yInM3NZp0liz/azk+NM0ptt3tkdXZSxGQ1vD3EDOpiep6s9EVSeW+y5e03" - "/1Qt+ie/Fseb1HnaE5AS+ieL7k+IHMwTzqDDcDofkB+6P8qfRkPtpAEkD9Bbxsa4J+RHyCgo" - "hZRRm/xi9sxZH61smMBUQUEiRzwyC6G3jLk8IY8PdvElWMdf/6745om9DQP0UhELxDjQW8Zc" - "ntDF6Z8CdXSoID/XuxtyTmlBHD0dcy0ALs4oCRLrdiBHpmDuncT7wdWenxZ+I5xhEgxMWHvg" - "2AW3Z+RpD4c/ChMO6WVhjZlMmRwscMjhQwo5WM9+hT8WgyQwCgIVtOLIFPQSSdyKDb7CpwXg" - "DLGa2b49g/W+1jc4LSrgcR1IJgdYpL5tk/o6i4YMYL/hX6TmYD76XtN0k9MPAE044Pt9/5ED" - "qmERQ8DBPWHNMlT6O08eaqqeBManRWn+vrEvUdAbJTVVO3zyHX0SrtXQCOAtAQd71BnVdFQ/" - "fvnQ6qGq9BOyLDcp1d83aj0KFJETqqIerj705Y9muMqgEcBbxhZwT1iVJSjt/dvOrR4q8oQj" - "+/tGtWtyFEk5XD132/saDJeVKhYxABwNFrNVMV7P2he3nDi3+oksaQkQxVMSVga7ABxYc0Lu" - "yZ+snjtxyxcarECqoIVUHXBUowGWSl1RFKVXbrj5xP2rH0tdNQGCeKqLlcEuZJGCFSckUfp4" - "9f4TN9/wigRq6JXQQjLkiC1U2xx0VOKnN91636MHQqN7EnxIL7exMthFm1+G1yeFunDw6H23" - "3vSpCOK5xjZaqKMCTodHtVVjgGryu5DT5ETIqWabWBnsojnhNJkm5Lwrwwpq9S20UEsBnDaW" - "mOWrhrOuaJ8/8MgBx1ydA8a0nOV9sjdwm6tnoXed48vcwSMPfK5VjHAmj0bwEuC0aFTrpaIp" - "4coTB2y1Mwe+VznLYmWwC5bNwq8+xxbZgyeuCGZwqbKOFuIgB/eEueL+RI03vq2U27Ogt4vZ" - "SZKLuUcrE65l4YjO1vYr377RmMQWyjm0LNsL4BQblf2yMAvaXwjhwC4CnP1Kw/qSETiFPUSA" - "A4x2IRPcHujFZxk0br8U2h43B8ye/RAOnKHXxykJd4Dx3AvmZOCQ33Fd7Zlwlpx+oxnXjgX3" - "Hyoap4XNohzWb6VWHHx62eHQbMt2WuY/teeegxXEw9qT5i2vZvAwzn6VT0CO02+McDpt6PSp" - "U+bf9N+MuEQF/YL4PICeL7a12UK9Wr5SclTlN1YMjv2cgqfSeHHIWm4H/lX0s/8wOCvnmbIT" - "WMbWA+D5NmNj3KuVOsgCyF2cMyq5i7NutjfOmtsyytkj46+wWDb7fW6DdSKFoxJi/zqXUvBc" - "Jr+EHCHNzMUdJWBrgJ5fNDsL6O61lFF6MWsGUevW8K4knMDZBOoXlvLecybXMmRVUrBEWnq8" - "98BCE+br8eUuWrWeUr95zr1JZNjQf5P3kpp8re05uXPks4F9tHOSALpGzsqu/z65sjuZlCju" - "GjkJMYDThUuGS+GcVIP2hsVtzP+/sfRf654Kl0CX6t2w/SqwxARx3nr8YVOPvxnAofl22P7b" - "0wXCu9Npj3LlL6auOD3pbQ/dpMP2E3fXsd1ps21xxc5ilbf/DPU2csfLqXXyYfuj42zL23Fx" - "M7k3pHx27NixzxT7WlY8HJqXlsP2e8e5Hd4DiqPJ8nev/unV75AbHg7NdvbC96/HSy3PVIhL" - "6Caf/LqMXbrbwzRF9ywg/S5gc80DiveABXAELYWtroRzaIbvPus9miGcl6xfEOp417k4GFTE" - "OTTb7G4QDmaI5z9rnQbL0A4rLl71Fcqh6RrfEZ+NeP4zHm8uXT4SeM5O+We7ARwZpsaG6nzr" - "qrSXiXyeBebkhcyFCmuPdkLq+qpnWD5DEkfnMhd+wfkcLArOG+20Yaaw66s92kkFfvl5I/6l" - "FgLPAad4TtsJOgecIifgHBB4wun9PgT3lphvrHtSKCI20u9qfJI6Yy33vjr/4Fg98Ee/hZ8H" - "k2bLAu4tsYRomvPN5S1RDvSEU3tOXd4S2yICnnBqHJe3RLMD6AmjKNJ64PKW6C8VoSeMop8B" - "XFekjMjBOHUAAAAASUVORK5CYII=") - -#---------------------------------------------------------------------- -aero_dock_pane_denied = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAYAAABQif3yAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "ABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjM2qefiJQAAELhJREFUeF7tnfmPHNURx81v" - "hEsCIQQCxCnu60d+AH5BCCGBAAkEP/AHABKKkEhCCErCHcA4WGAIYJwYbOMrGHzgE9vYxvje" - "9drYa+99etd7zHov766PSn3avFFvu3v6dU9Pz2Q9K5Vmtt9VVd9X76zqOWtSCf4NDw9LfX39" - "pMbGxklHR0YKxuHvzj570tVXXz3ptttuO6tgjUykioeGhuTbRYukrr5eRkZG5OTJkwUj6qcd" - "2ptIOiyYLFV79khDQ0PBAPEDm/Zot2BCTZSKFy9eLGNjY6mCc+zYMaHdiaLDgsmxYOHCVIHB" - "kvij3YIJNVEqLoNTwkgWAxysp2w5Fp2iDI6FkoqVxYBz4sQJSYPM6q1sORaIoyRAOX78eCpE" - "W+VhzQIYsgAOwLC8TYvK4EQAB1DY66RBtIX1lIc1C4BQEgobHR1NhegAZXAsgDHDGgrj3CsN" - "ohMwjJYtxwIglITCjh49mgrRAc5YcGpqa2Xjxo2yZs0aWaiKR/m5aNonn0hLS4vodUEq1NTc" - "LO3t7UK7YbzBP3IgD3JZ9LXSzLJj505Zvny57Nu3T7p7eqS/v9/qzGzBggVO3h4tkwb19fU5" - "wyft2lxPGN6QC/mQszQR8OGqqqpKlv3wg7S2tloJ61UISjpy5IgcPnw4FaIDMITaguPlFzmR" - "F7lLGqRdu3bJ1q1bnTHcphf65UFJvb29cujQoVSoq6tLuHmNCw4yIC9yI39JAlRRUSH7q6tj" - "g5I9RlFw6M1tbW2pUEdHh3D7mg84hnfkRw8lBRC3iNu3b88bGGenruDQm5t1oo5KKDpqGSx0" - "cHAwEXDgHz2U1K0qEyMbx7hDmbtcXHDYSDa3tDsbyigAsVJLEhz0gD5KwnpYrcSd/IPmnKiW" - "MzZ2TOoaWuWPr051PvnfFqCkwUEm9FESq7jlK1YkYjHuOScKOAMDA9LRmZG/vj07S/zPcxuA" - "CgEOsqCXolpPtU6ABw8eLBo4AFDb0CX/+GjNacRzG4AKBQ56QT9FA2j9Tz9JJpMpCji0W12b" - "kQ//XRVIpJMvlwUVCpxebXfDhg3FA2fp0qWJO/7ZLAhYalfXD8nsJR3yr7ltgUT63oODzr4p" - "CKBCgcP5IPopmuX899tvndVREqu0KHMOe6DhoyekKxNOg5qP/GmDgzzop2jgFMIZ43t17mO/" - "woon13CEwskXRrmA4YC1s7PTOS6i3SQ7WdFvVwsBDmdUu5VYsbFBZNgpFBlgOMTcvXt3GRyb" - "3slwgMKYK9ggFopYLOzfv98Zfmz4ipqnqBd4hXRjqqisdPyX5+txTqGI+mknaResknC3KiQ4" - "SSsszfrK4KTkdBgX1JJYEKTpAJiWo2G+7STuqLh3715n0xR2j+5O59496nyweMkSZ2WUlsNg" - "Eu3AL3xHkZXNtI1fgluf6B8cxu2N4ob5sRTFfKOYPlfCtXV1zgrJT3HcSm7dtk2WLlvmHB6u" - "WLmyoLTmxx+dC7IgEOETfuE7ipzoxejHdpV3WhhkPmF+NB6FYXdeDciVSl0peZWybv162aO9" - "B2Wk4VjIMh1w/ACCP/iMI2MccAyI2TDIfML88gEHx8Hvvv9+HDjsO37QiyrbnpZUPgBatXr1" - "aR0F/uggaYOTDYPMZ5efDzgodv78+eP8odl0couYlNJt62EopV2vbzb8xQHGLAiiDmuG32wY" - "ZBmck473TRkcz95knvZM97zSE9FyRvTgs2X6dNn3zDNSdd99DvGdZ6RFtRzvHAd/xbCc7B4p" - "H8vhRDjungChg8AJu4Y4zssd3nxTKq64QpruvVd6nn9eMq+9Jn36rOfFF6Xp/vul4sornTzk" - "DQPJWE4QOHFkRAb0E9Z2ULpzLpfPEcwhbTzuPgKBAccdScAlGsNLrt46qouG3Q89JLU33yyZ" - "d9+VgVmzfCkzebLU3Xqrk5cyueo04HijGuAvbiAX5dBPHMsbZzlUEEfJHOUzidoseU1AFHkp" - "4wdOd3e3A04QL2O6vK56/HGpv/126fv4YznyxRdyZOZM6Z87Vwa0p0F85xlp5Km/4w6nDGX9" - "6oUPnApp1w8cd6wQfNvEDpl86CeqXo23bNZy4vYOLrJsgaltGpL+wePZ/DDttRzAYSlthPMK" - "1qIK//XSS6Xr9del7/PPpV979oC+t2bQQzwjjTzkpQxlgxQFOLTrB46788E/ctgChH6igjMu" - "0s5EksUJ8WvVxsMCnGhsT3W3zFx0SBrbT0WrUcaA447DMeAY63LzNKoK3HXTTdLy5JPS9+mn" - "MvjVV1ZE3tannnLKUoefnAYcb0yQmRPhF57gHzmQB/5zyU5+9BNVr77g2FiANw9XyTAYFOh0" - "7NhxaTuUkY9nVsknczTmRoUz+WF63rx5zjLWELefpgd72+pWT5bKSy6RHp3kB6dNi0S9b78t" - "lZddJtThJyebUNp188J3+DP88gn/yIE8yIV8QbKTH/1E1eu4MEgsJ26YH3f8CEHP89LIyKh6" - "X7bLW1NXyZQvK7PgIAxlcoFDurdXNrz3ntTcfbcMqKI7dXXWpRbRrcNWr1JGqY/5R6lfaRDS" - "ZwOap++555wytffcI9Th19vxbwsCB36RjU8DDvIgF/Ihp1d2+Cc/+gkbWfzSs5F2JszP22ts" - "/m9qavK9Qqa3tLV1yqtvfiVvfbhSpkw/BU5D22gWTPLM1Z7pFowdNUrimbf9mpdektZHHpHB" - "l1+WtqeflhNaPuzvpObpffhhp0zro48KdXjrRTkGHK+S4Y/8WBaf8I8cyINcyIecyOK9Sqcu" - "9GOjR3ceM+RnFwQ88Ov9Yc84oEMwor0MUaZqb7W89Mo/5S9vGHAqZJoDzql2KEObCO8WyoBD" - "urftuldekfYHHpChZ5+VVlW4LTg9N94oA7paa3/wQaEOv14O73QKr4JN5yGdcvCPHFOmVzjg" - "IB9yIi/pbj1QF/oJ06EfP8w7WXColMk4KuGEwUbLG+hEfc0th+TPr/1H3piyXCZ/vlM+mtUk" - "dS3DTuwNUWsAMOebb8a1iasSUWKcsXl5adBhqvGaa2ToscekQ0Fqf/996fjgA+nUvc5hHba6" - "lLqVmF8ySn3vvCNHdH7KXH+9DN51lzRee61Qh7de2qJT0K43Df7gF/n4hH/kQB7kQj7kRF63" - "DtAJMjohlxH1yuGvEwZpNqE8gMGotEfjclguMvG5yXH602HgYG3raeAw6cM8AnnBYYzmHoc8" - "Xl7ata09uiAYUksY1n3O8J13yvAtt8jwDTeE0pDmoSx1eOs1bQWBQzqy8ekFB/mQ06sD/gcs" - "9BNVp4DphEEacOg9cXzDKvWGEIX6RT4z3jJZNrd2y9QZFfLR142OcMZhkEDZ2XPmjIv7pB7A" - "QSA/fvY+8YS06Z5l5KqrIhFlKOtXp7F82vXGocIfvMAX+RxwVA7kQS7kQ06v/DwDUPQTVa+0" - "50TaGXBAiyElKhEDybjKhVQQMRxU/tohMxa2SG3zsMMsgGKtRnjTuww45PHjpWHTJtmhFtB5" - "8cUypgq3IfJShrJ+dRrlmU7h7unwRzqy8Qn/yIE8yBUkMzoBIPQTVafZMEgDTpR4GLeL7E4N" - "nILBWo3Jz0X0yM27uqWj62i2p2Gts2fPHjdWUxdKyuVCWztjhmw5/3ypvuACGbrwQjl+0UW+" - "RBp5yEuZINdeE3tKu965E/5IRzaUDf/IgTy55K3Ta206GvqxiRFy58k61qcFDkpHIAREKBin" - "581S4d1mj1Bh4CBInZbbfvnlsv6cc2THuedKzXnnSdNvxHeekUYe8ob5XAMA7XqHIPgz4BiA" - "kCOsQ5YMODBSU1MTidzguKOmcaTAAyWX5RhFN+p4Xv3CC7L9uutkkwLx02/Ed57t1zTyhPVc" - "t+V4I7gBh7kjqnwAydBWdMvJFxz3Kg+h/MABTNLwa8bRfceOHbJlyxbnNSfr9HUna/REYLXe" - "5zj02WeyVv0BCFz65ZdfnOhmXJtY1qJklOYGzA2Od9V5RoKDgpxhTe9i3BMmygsChzQUjEfM" - "NnWd+vnnn2W9euqsViBWqAvVMh2WKMvR/6pVq2TdunUOeOblDfiDEQpoJmsDUBYcLeudvOHv" - "jLOcXOAssRjWmLsMoWSUapTtVrCxhFwvnGB11KJDF6CWJDgspcPGZr90xtQ4wxrg0ObX2jPd" - "9dKzbcAxgDCBU09YAFWudI71N6kVQl4Z4a+oloPfGmv7sEiypMBh7qAu2uTsyguO7YIAfhka" - "cZNFBl/SNHzPoKB0ItoYHv3kgz8sNGoHjLsgcEfaOa/vx+OTSZYeGDWSjIkW5rEEWzLA4GH5" - "o7rC+oETtAl1DzvuzaPftQXPOC3GullIeA8YOSLhgBF33wMHDviCA3/bdEFBR2BRYisjeSmD" - "fqKcELgj7bJvoYobSVavoLDTj3K4xxBDwNIc3X379dZF333nDFNhdbKJ3aUAo9ygV7sMKwAr" - "NZ2YTz8vFywPP3GUGTSswycdyQyhYXyRTr20iX6iROU5kXb67oLTAn1BmfE+apQBzDM22xK3" - "iziPBylj8+bNjsIChyrXEIYL7QZdkSGMH9+LtB42l0EysQjYqUcsYfMt/MK3rYwswRkSo0YZ" - "oH9wSCQCG6HjHv2EKYQNaRiF1VGs9HFHMIloOkYlhQSnWIpNot0yODHex5aE4m3qmPDgrF27" - "1vFrsx3n4+SjftqxUXiUPBMaHG5I9+nylxVPId8vTf20Q3tRlB+Wd8KCw96CV2EVEhRv3bTn" - "3XOFAZArfcKCwxIU/4I0wcHZxHta8X8PDvsLLp/cB4/5CEVZ5g4bYDJ9w9LaMRRKPZlTDn65" - "CG8X7zlfPnJw0gLgRX1rFOdg5qglH2HcZW3B2b2/V+/zm2TqzPpAIn3HnlMv9U4LHHM+xglG" - "Ud+3xpsKORS0ubm0Bc8WHJS9Wx0t3v10eyCRHgaMSU/KcgCHjTmfRX1TIRMpxx9x3uccBJYB" - "x8aNFcX+Wt0qf5+87DTiufHLDquLfEmBQ0fljAy3qKK+45NDBW4gjWuVrXXkyoeSgpzj/Vxb" - "UWxTc4f86W9fZon/jQN6mDuscTpPAhwzpNEmTooxDl2SLcL7k9krcNydxMIAJYUp1Js+MDAo" - "+6rr5Pd/eM/55P8odSRhOcjO/IvVHNQr9ZJ4rzRQc5qK9SSxODDgRDlqN1EANbUN2aiAKOWx" - "nnwtx7jssg0o6kLAa3tcDOFMkQRAKAnFuj32bb97Ix5sypmIhrjgYDEAw8hBXRvVs7Tkfq4F" - "11NcloxXftwhLh9wbMDwy8MQGAccM5SxOgMYLv9K9mdaYAwLYtxlc8owR68y18s2CwaUhAJx" - "dE+DTOyNLThGFlZlWAuyUgcWU7LAmKEOk2YOOqCeNBwsYkkIwXLb5j6dW0R6YRrA0AaKZc7x" - "ugb78crOH1kYvimLxRlfu5IbynKt+xjimBj5xAnEHAaGTdQmmgyA0iD48Yuy8+MTMBw/N51n" - "cBwx8iW7/k2xNvevHdr4J3DvzqkDG7g0iJ6Psm3v+yfErx3GxR8Ai/KDeoRclP9yawBwmGRT" - "/0G9MjjhXRNw0vxBvXFhfuHsndk5ACduGGTUED/yZ39Qr2w54R0vbXerkrhSDldLaeQog1Ma" - "OPhyUQanDE7WFao8rEXoDGXLiaCstLOWwUlb4xHaM0tpmxPsJPKUh7UI4OQTBhkVrNPC/CLw" - "eUZmzScM0uZKwp3HN8zvjNR6BKHjhkGGXUd40wPD/CLwekZmjRMGaXMl4c6TaJhfAVD6HyAO" - "VvwtWIicAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -aero_dock_pane_bottom = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAYAAABQif3yAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzoyMTozMiArMDEwMExUiZ4AAAAHdElNRQfZAxkQJgE7q5VA" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAEFtJREFUeNrtXVtsHFcZ" - "/me8a+9617Ed3x3HcXNxnDhxmsShQQqEolKq0pLeVakSqA8g8YIEQvDAC0g8IB6okEAoPEBB" - "QEvbJKWFJqBSWpSUosYpdpzaiXN1Yju+xJfYXtu73hnOd3bPerz3uezMoPqTRrM7u3PO///f" - "ufz/ucxI5EKEQiH16tWrdP36dVpYXCxYPn6fj1paWmjdunVHmpub33Bab9djfn5ePX7ihHrl" - "6lV1cXFRVRSlYAfSRz7Ib3Bw8FmndU+G5LQAyeg5f14tCwZp06ZNtuV548YNmp2bo47du11l" - "D9lpAZJx/do12rBhg615NjU18XzdBteRsxQOk8fjsTVP5Id83QbXkbOGFayRw6CqqtMipMUa" - "OS6GvY27DthVmiXJVQ7aKriSHBBjZ1PjVoI+8eQgn6KiIqdVTotPPDmoNW51CFxJDuBWg9kJ" - "V5Jjd5/j1oKwRo6LUXByBi5fVm+PjNDS0hJNT09TLpOPjY3xIxqN2mIASZbJ6/HwPF997bWs" - "4sGnq6iooJKSEqpvaKBtW7cW1M0rCDlHjx5t29/Z2TfOFI6Ew7Rj504q9nopGAzmvPfYsWNU" - "Xl5OkUikkHonAE/N5/NRbU0NPfnEEzn/Pzc3x2UbHR2lkydPqjW1tdS5f39BSLKcnJ6eHvXm" - "rVtUX1dH+/buNZQGmjS7ao7IL1+IAlZZWUltbW00PDxMf33rLXVjUxN1dHRYSpKl5Jw7d05d" - "WFigLz74IMmy8ZEhEGNbs2bSlW5sbKT6+nrq6uri+u/bt88ygiwbW/voo49Uf2kpHThwwBQx" - "AIylKIotBwqBWecD+kJv6A87WGVTS8jB7OXy8jJtb221RChhNL0H+g+991jpGUJ/2AH2sCI9" - "S8gZYn3Mvffea4mCRoHZ03BE0T2LarXLDjvAHlbANDlnu7rU3bt3Ozo+VV/fQNcHR+jnR1/l" - "Z3x3CrAD7AG7mE3LNDnj4+O8U3QK8Jomp+boty+9R77San7Gd1x3CrAH7GIWpsjp7+9Xt2ze" - "7JgRQMDoxCK9+EoXlZbVJQ58x3UnCYJdYB8zaZgi5zYLxGpY8OYEysrKaGh0mf7y7gj5grUp" - "B67jd/zPCVQzu2DUwQxMxTlzs7Pk9/ttVzwQCNDoVDF19c2Sz1+V8X9dfUu0Z3uQGquDPLK3" - "VUbmVt+9e9dUGqbIwXIir9drq9LA4uIiNTdUUFWlL+d//ewvM5MztssIu5hdbmWKHMQjVk/x" - "FpeU8PgDgR3STwf8PjV5Oy8PcSaUebQBsovYCPlajUzy5wvXTRnc09JCo6ytbmxo4AFdtjgk" - "H+VBQKZFimLQc2hoiFpsXP6bL1xHzq5du+jE66/zYXyMWRUXFxcsL4wuY+Cyr7+fHn/sMadV" - "T4El5FgdZT925AiGQOj06dO0uLRUMOV9rCnb2NzM87NSB6uaetfVHIEOFmXj+CRjbcVnAWBV" - "LTRdc9bm+1NhVbOWSKW3t1fVu80PEbDeEQJ4R5tYO79z506bTGUeH3/8Md0YHOTxVb6AYcfG" - "x6m2tjbve8Q2SOYUSSINwra7PXv20IbGRl3eEQb3QI6emhNmgdkQ85C6u7vpy48+mvI7PKjz" - "vb08bbi6hV4qCze7av167iWmwxtvvklGbAO5hX2M2OaJxx+XJDPb/JB5dXW1IaNgqx+GN9rb" - "21ddP33mDE9z65YtpmdU8wEKw8DAAP+cTNCFCxewmdeQbYyQo7UNtkHKTmzzA/hWPyaEFhj/" - "whqEdtbkYfkRhkAKfZSWltK2bdtofGIiRUbI55htGC8eJ7b5AcgzzGIYbZOIz06s90cNjaYZ" - "jYB8TtkGvKy50i6GY0Eod8FpdUzgtEOeXHOckkfIYYocMzFONi+MN28u2tBkVEez8V+CHCMJ" - "qQbvy6hAUv9jN9LlaaYAGrWPKJgeIYCRuQeV3ZOv8Oh0xX+RebqaIdIxOw+i1xDZ5NfaRsid" - "Sz6hmxpfuKhXHnG/rDWKXugh5sZwmBbDcs77rKiNenUQ+Wb7HYD80CNX/CX0M9Qaae7zJF/Q" - "lRDlNiSi/P4rM3SuL0KH71tPDVWU4j5nM4idyNasoTRP3o3SmXN3WSzmpbYt5TnXcxspaNoW" - "xVSfI/qITPd6PF4am5il9/4zTLK3cpWy/J6kQqHmSK9QyJhvSg2QaH5hmekzTuvLi6i2uoyW" - "lyPZEjalS6JZM3JkWyAuSTIN3hqjF1/5kMLLikbe3AIrmr7MriMbcUIeAegDvaAf9EzWXWsf" - "IzYVeclaAfQemQRAhHvnzjT95g9vx2qXmihIq/+bVDBE52nnLoNkIrLJl+An9gPXD3pC33SF" - "1oge2hpsuuYkC4A28+LANXrhF3/UeMYqiW43uXSkK7121pxMsmivrfxnRQ9R2KAn9BVeXK6C" - "m488ArzPwVB12MAaKwxSzs/PpzQLLc2N9M1vPEu//PXfUkoG5kRERyq+J5oLJgPSwkixXe40" - "PC/kh3yT52uEfJAL0wWK4k/RB3pWlAdWLSAEUUgX9sGhB3CghDfIyTG6k0y7x0WL2dlZqq6q" - "pOefe4D+9Mb5FIWT23ABUXqQpl3k5NP/ZZIH+lVXldPU1NSqdETsZNSuKa60IXKyCI65jOam" - "evrqMwfoxN9vJjw7/B/r0bRVX2sIrUHsQKYmRfyGa5A3MTrNrnk9Mj3D9IK3Njp6O4XgxGJF" - "g3oIOTxmjKFkqDkCw8NDfGf04fsaeJyDvyXXnHT32rknVItMsqzITBTwF9G+fQ3sLHH90kHE" - "KooBPbQBrrkgNEOJ0wJVvrFmHYWW/BRkCi2FIqvinHQ1x85FI8mOSNKPCf3QLwVLJWrb7Gf6" - "KFyvTBBDMEb0SHGlCw3McG5tUhgxY4nnC6R3VZ2dNEjnSgtAbsgPPezasWDL0ihU7ZmZmYz3" - "Jz7HLtiieC5Z0umnx6u1oqA5vuIz05SB47K4AI6QkzBChrE1R5CuBXCYLMdrTjL0mEN0vGZm" - "TeHyRpir7ManFXqEknZD6xBor+ULEUsgckccYhTLrD/EOrGydetS8ne6kfOUMOVy7SSzEtrd" - "ZOm2LOZbTJAO1radef/9zM2PZtZSTlcA4+5uOSNmc5pd4ZDPKduAF0/LPffwx1Nh77wYY8oX" - "iJpx6BEcmcOo2LRUk2G1aD5NFQyGZ7jh/Pn7788Ypff29vKFg83NzSn3Q/Z/vPMONTSkf6gE" - "5Mt3l11y3sI2eta9rdpp19JCHrz54tjx46rHwE4ybGzCclU9UTCUHB4Zob6+Pjp06NCq3yAY" - "2n8YLpcc+A9WZEJulPB0fQbkm5iYoIMHD6bd9Y1AMhQK8cKSDlgJig1c2GVXV1eXt20EOWFW" - "2GGffMF32sE2/f149ttK8ezu7lYHb97UtZIeuwwqKyr4GFK+wEPxqliJbGWKp8OtW7f48w08" - "eXTQPmZwEIpxvHS1F2l4mUEzjQwHAwGqZUavybHe+9LAAN1hJIfzfECfIOfOnTu6dhlAl+aN" - "G7FwfmWXgVHgsYufO3xY97B4PsjHEMUObLPPByAGNebkqVP09FNPGbax61xpAbca3k6srZV2" - "MVxXcyZCsfONSz3051ulNLZYuPJT61PoSFOINrV28O/VpU5rvxquIwf4/qmbpO74Ej3wnEqb" - "/RLBzypmLTd8JQ87w1XIlzI4v/Alo+wDQtUldobLg3HlgZBKR/8lkXzqffrRQxudVjsFriPn" - "2sVukrY8TD/+dJQCKotVmDU9MshgnyUeN3IvRk8vC4LgyymY7GOxyjKIYhcOSCo9eb9M3104" - "yPJ9i6r37nFa/VVwXZ9z/GaAWg5JVBzNPnwiM3ZAWq5DzsIiSPJGFap8KJav22Cq5ojF6Va+" - "SWMqLFOrTyIlS7gFgxezdurufO48MXupsrZQyfBX1KhGv0wXwtaVU2EPs3taTZFTYnLQ0SiK" - "mc79A/P09r+naHImc/7ryz302c4K6thVRss2LUkQy6IQ7ZeYfG6PKXKCZWU8AEVka+WCDJRm" - "NcMBLLKsdrQFCdXrxWMXM6bzzIPbacfOMprX8KddtCnGFKwe0wQ5WM+nZ+gmHUyRg0fiT8/M" - "0IZAwFpy1JVVvPwM48mxz+hCmJ9AIWbw9vYa+lpRhF741bspaXzr65+j1rYamouoq9NSNekX" - "YE5ADKjemZzUNXSTNi0zN7e1tUl4wweEsXJOCGRE4h4VXGDhCic8LiV2vhtWqXV7I/3wO1+g" - "2akbiQPfcR2/KyoljmjSZ6QfUVZqkFmIMTUMkGJkGfYxk57pXrCuvp4/RgQCWUWQwpcjqbFz" - "/FAZY/wzxY/49ZmwQg11FfSD7z1NodlhfsZ3XE/cS0lpaNPla9KsIUZM/uEpHBjFNgvT5OD1" - "JFeuXOGCWfU4FBiLxyKa0q4t9YqoRRSrVRPLRdS+YzP97Cff5md8j9LKfxK1heI1UV1JP6Ja" - "M+MJvcXUxaWLFy15bYsl/iMeNIT5GZQaKwgSzZmS4VCTDlwbXiCqaNrEz+n+I/qcVWQJYkzU" - "HOGdgRg4Rt09PSkTe46Sg/fG4HHCeOoUJq7M9kFKvERHNCVc2+9oa4D2WIimvw5nTdTCaLxW" - "RuL9TTievlFixMwuZlsHLl/mjyy26j06lkVeeG8MShAef4USJEjCNb0rZBCTRKLxGqQ5lLhx" - "hUOQ96HEak1UWSFIOARwMvX0OUIX0b9ghhW6/re7m2di5ftzLB1bg2B48xSe/NTa2spdbQSp" - "Yv4937UGsT5BZWcczBCqFO9n4kUc42s6SrtKq709ni5qUHzYQEiVa75fNGEgRkyPYy3ERdbH" - "oClz9ZunACHg2bNn1YFLl/i6BDzWCorkG5Rh0GFZiZdsOWZYGUaVKNF7yzrMkOxOC/cczZmk" - "rtScXPKBHOw9QuCNKfqRkRGu3yOPPPL/8c42gc7OTi4w3nY4ODjIV8pMTU/ncWc1vTypUh1r" - "19aXSFTmlShQJJGvKDZs45Vjo9NFOswhRqHDjJ0ldp5nF2YjGMdTWCWU6CWW1mH2P0wr50Kl" - "5m2H+wv0Ij2Bgk8Z6H1d48M/fVddZDVnjhmuRJK5gEXc3ZJILYr1HXrIEU0ayFli5GDoZ4GR" - "E2Lexnw4FutEIrHRDTPz/YWA6+ZzgKVIbHimlElXwuzGKg9vxkRThgk3RSc53DNjaS3FD3h2" - "yIM7Cvbv08oLriQHrto8K+oBZjQf62iK0ZRFV1xLVSc5fJiGsRBG7Ymi9sSO0HJsSfAaOXrA" - "SjSatiV2hFlThqkWT7wp45zIMYLygSBHjKMlalA8D441cvRB0RzZpg9yIdO9Im03w3XT1GtY" - "wRo5LsYaOS7GGjkuxho5LoY7yZHtE8ydBojBda50tV+iAPNxg8VywQ3nY9oHvDKVxfN1G1xH" - "zvO7vfTPniLa8Jko+VlwGGTRZ9BL5GcRaElRbODTY2BsLaJI5FNUKmH3e2WViotUquHPspGo" - "6qREX9nrod85rXwSXEfO/o5d1P7hB/T7Cwdpx6dU2lYqUwUjJcjI8LOqVMLO2Lnj0TNCoMZm" - "PBfYMc9q5TQ7JhljlxaJhk4TtSkfUOeeXfklaCNcV5dVhunpafqw5wK93K/Q7fnCxfH1AZme" - "bZPpQEc7VVRUYL7GVfb4H1Voiukj7VWUAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -aero_dock_pane_center = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAYAAABQif3yAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzoyMTozMiArMDEwMExUiZ4AAAAHdElNRQfZAxkQKidFE1+x" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAEAxJREFUeNrtXdtvHNUZ" - "/2Zv3l2vb7HjWxzbcRzjJCQOcSKQiBSQEBclFAgX0VYt4qnq9blP/Qeqqi+t2gi1BaQCJYQg" - "oAQQD6VKHhBxwCGJc784dhzbcRzHt73O9Pxm96xnd2e9c9uZqdifdLT27syc832/c77zfec2" - "ArkQS0tL0pUrV+jatWu0HI2WLZ9QMEjd3d1UW1v7TGdn54dOy+16LC4uSu8fOSJdvnJFikaj" - "kiiKZUt4PvJBfqOjoy87LXs+BKcLkI9T330n1UQi1NXVZVue169fp/mFBdq+bZur9OFxugD5" - "uHb1Kq1bt87WPDs6OuR83QbXkROLx8nn89maJ/JDvm6D68ipYAUVchgkSXK6CKqokONi2Gvc" - "dcCu2iwIrnLQcuBKckCMnabGrQR978lBPl6v12mRVfG9Jwetxq0OgSvJAdyqMDvhSnLs7nPc" - "WhEq5LgYZSfn4qVL0q2JCYrFYnT37l0qpfKpqSk5pVIpWxQgeDzk9/nkPA+9996qxYNPV19f" - "T1VVVdTa1kabenvL6uaVhZyDBw/2D+7aNTLNBE7E47R5yxYK+P0UiURK3nv48GGqq6ujRCJR" - "TrmzgKcWDAapee1aev7AgZLXLywsyGWbnJyko0ePSmubm2nX4GBZSLKcnFOnTkk3xsaotaWF" - "dj7wgKFnwKTZ1XJ4flrBK1hDQwP19/fTzZs36d+ffCKt7+ig7du3W0qSpeScPHlSWl5epice" - "f5w8HuMjQyDGNrNm0pVub2+n1tZWGhoakuXfuXOnZQRZNrb2zTffSKFwmHbv3m2KGADKEkXR" - "loRKYNb5gLyQG/JDD1bp1BJyMHuZTCbpvr4+SwrFlaY3of/Qe4+VniHkhx6gDyueZwk546yP" - "2bFjhyUCGgVmT+MJUfcsqtUuO/QAfVgB0+ScGBqStm3b5uj4VGtrG10bnaA/HTwkf+J/pwA9" - "QB/Qi9lnmSZnenpa7hSdArymO7ML9MbbX1Iw3CR/4n987xSgD+jFLEyRc+7cOWljT49jSgAB" - "k7ej9Pq7QxSuackm/I/vnSQIeoF+zDzDFDm3WCC2lgVvTqCmpobGJ5P08X8mKBhpLkj4Hr/j" - "OifQxPSCUQczMBXnLMzPUygUsl3w6upqmpwN0NDIPAVDjUWvGxqJ0cB9EWpvisiRva1lZG71" - "vXv3TD3DFDlYTuT3+20VGohGo9TZVk+NDcGS14bYJXN35mwvI/RidrmVKXIQj1g9xRuoqpLj" - "DwR2eL4a8PvsnVuaPMS5peKjDSg7j42Qr9UoVn6tcN2UwYbubppktrq9rU0O6FaLQ7QIDwKK" - "LVLkg57j4+PUbePyX61wHTn3338/HfngA3kYH2NWgUCgbHlhdBkDlyPnztFzzz7rtOgFsIQc" - "q6PsZ595BkMgdOzYMYrGYmUTPshM2frOTjk/K2WwytS7ruVwbGdRNtL3GZUVn2WAVa3QdMup" - "zPcXwiqzln3K6dOnJb3b/BAB6x0hgHfUxez8li1bil7zuze/oKszMQoG/GVfjenziNRZH6Df" - "vvxo0WvOnj1L10dH5fhKK1Dqqelpam5u1nwP3wbJnCKBP4Ow7W5gYIDWtbfr8o4wuAdy9LSc" - "OAvMxpmHNDw8TD94+umC33/9189ocGsvdXa0UjjooZDPQ1U+gQIs7vEyI+xFbOKBPRZID28o" - "okgSpZj3nZLSnzHmit9ZiNHvX/uCHtpSr0rQhx99REZ0g0rF9WNENweee07wmd3mp9ekQUDE" - "Mh5W+DNnztDWrVtzfl9IEj390Ca6siBRiMWYQZb8HharMEIYR/J9HiHdWeppUygloiIRJLEy" - "J9mnl30RYh7bL3+ylw59/lXBPSjfAzt22LYFUqkb8OJxYpsfIG/1u3495zuMf3kzzcHOXizC" - "lJJIFeaI8jmmG8aLz4ltfgDyjLMYRtnynHYs8vNH+ZzSjcyLo9pYBTBBkuKTKLc16aVR7V7+" - "fLfCMXJkF5xya6uUSegX5I6bWTjRw/uJdB/D+xk5QNPtEKw8S5kkRZly7nFQN4ApcszEOKu5" - "yFBiEuR40iSJQlqJnsxvQuZTTwTNSZA/FcSkpNKtx6iMZs10lhwjD5IM3ldUgMzf8KbizM1N" - "sH99EnOdQYzEGwquSXtseqq20lNLZUiBxyayL8UMPWqymKmARvXDK66PF8DI3IPE7tFaeMzP" - "8GuRuVrL4aYua9bEXLMmtxp2m8BbgU6zpmraKNe0qZWJ64aXu5SuuGxSZuGiXmL4/R5eACPQ" - "Q8z1m3GKxj2a7oOy4kymRKZ2pxTmhys0Jan3H8WS2v3Z1lNCRg6UH3KUWtHK5TNkjRT3+fK/" - "0PUgKk0sJrTOXZ6jkyMJ2vvgGmprpJLuM5QWZcFokOkgIGBUQBF0ZrwCj85RHSVJIAR9WkJc" - "+b5YWZSt/c69FB0/eY+Wl/3Uv7Gu5HpuI2ZNaVFM9Tm8jyh2r8/np6nb8/TlVzfJ42/IEVbK" - "2Bk1oqCshCQyJQo5LcfL/k+bNkm3KyXmmbQU73vE9FCOqhwFLUCgxeUkk2ea1tR5qbmphpLJ" - "VbaqmBwUzpo1I2m1BeKC4KHRsSl6/d2vKZ4UFeUtXeAcsyZmPDdOEuWZKK2Jcu9P8WdrMGti" - "pm/lgDyQC/JBznzZlfoxolOel0dZAL2pWAEQ4c7M3KV//POLTE+crUi51+ZVDPlZlFYaq6AU" - "Q8qYn4SoIIonSUfK3MOfwZ+ZYGwlU7kVp1j5svykf5Dlg5yQV63SGtGrsgWb6nNEFW8Nfcz5" - "i1fpzbeOUlV2TZmU4aewdhSaEqJ7rMl8PBqjDREvtYY91FAlUK1foGqfIA+EBjIDoeiLtHQ9" - "Eq20lDhrRlFGxiJrMsgnzr6fn1yULyrW56ysMlqRg1e2P/75Lfrpj56ijRvW5/RBfPWQXr3i" - "Hr6qSCYHQ9VxA2ussFFqcXGxoADdne30m5+/TH/5+2cFNQNzIlwI/j+HXAYpXaNn2Z9rWMuJ" - "sFTlw8h0mgywwYdd9JKTENMtEeQss7SUSpvPWMau5c/X8PKhXBgxFsVQgTyQs76uOmcBIYgE" - "OdAPkh6AGO4NyuQY3Umm3OOixPz8PDU1NtCrP36M/vXhdwUCF6tR3JRAiXOsn11kaYmREwZB" - "njRBntTKyIBogJx4SkFQcsVMSkU8DL5XSC1egXxNjXU0OzubIw/fLWdUrwVmzRA5qxQcE02Y" - "MHvlpd105PMbWc8O12M9mtImKxUBNSXZ9/dYlV5ICDI5yymBQilBNmdeeT4H5jFt2rSSI/cz" - "8sgDI4cxhbTMUoI9N5GTf66S8B3Kmx2dZt/5WcYvMbngrU1O3iqoaNnFihn96AUvh4//Y+gh" - "RVoOx82b4/LO6L0Ptslxjhyh57UctXuz3prSAVB6XoqRA63kZO9TxDvcQRAVDkE+eOVLl5mo" - "OuSlnTvb2Kcgy6cGHquIBlqOMsA1F4QqvJNiQJNvX1tLS7EQRZhAsaVETpxT2HKcQ0H+Cvmw" - "ADESFqi/J8TkEWW5ioEPwRjRa4ErXW5ghrO3Q2TETGXPF1B3VZ2fbMt3pTlQbpQfcti1Y8GW" - "pVFo2nNzc0Xvz/5ti8iry7KafHq8WisqmuMzoWpTBnYjHYk7P02eD0fIySpBZWxN1KEfDH76" - "MytyVs2P0hN3PuZ7C6n0fJC8AgdzOX6JZlJRCvhUDotwmCzHW45RgJgwU2hjFXMyoqVNjTy2" - "5mGEsM84oyvKUrOXfS4t0emh07S1w/5NYKUgk+PEGZeqawjY31qnAtBimoIC/eGNo6u6q/zx" - "xUSs8hJtbvPQU1vWuGYNAYevKhAouZPMSih3k6ltWYR+sHiwjv0U8aN1EIV8aSUGPOnk95K8" - "CnRpYYnVLole+8VjqoEgAsfjx4/Lm3Y3b96c8zvkRf5vv/MO9WzYQJ3r1xeUBb87pRvw4utm" - "BcPxVNg7D3dRT6cI4ZH0FByZ47wybFpa29RU8PtyLE5hIUX71geoiZkstI5axkgEJHkFCmRW" - "gGIQ9OvhcVpTlZKfp7a+bJGZLOxa27dvn+pxYpAbY2JNKuUAUD6tu+zylcx1o2fdW85Ou+7u" - "dIB9+P33pc39/bp3kmGhdkN9va4oGEJO3LpFI2fP0p49ewp+/9vn39K3k0kKBkrv96xj5D3a" - "lqSpiTHVMqDmQ1iM9amhvq6OOru6qHfjxqJTz9jAhVbX0tKiWTecnJk7d+Rz3LQCjQPHB2Dh" - "/PMHDqxY4uHhYWn0xg1dK+mxy0AmR0fLwaF4jaxG9m3apPr72NiYXECfhs24wVBIVj7G8dRa" - "L57hZwotNjIcqa6mZqb0tUVaDseFixdp5vZtims8oC9LzsyMrl0GkAXmdWBgYGWXgVHg2MVH" - "9u7VPSyuBVoUEXBgm70WgJja2lo6+umn9OILLxjWsWtdabcq3k5Uth26GK5tOZcuXaJp2Pky" - "vnQIHTz6m97eXqfFVYUryTnGYhMcKjc4OFjWcwj4TjLkt+fhh50WuwCuI+ci84xwqq4du8mU" - "O8mQ76YiHqRTcF2fA1Nm9+F62L2GfN0GUy2HL0638k0aCMS0nEQVjUm0GC2dZ4gFquHg6t4s" - "8rPykHGuD7OnBJsiB+M/iPidwOhElIbOzNP8YvHRiZpqL22/L0Jbe8O2lYsviwLZVSb7S1Pk" - "RGpq5AAUka2dJ6gDfd0hIjFOn/73RtFrHtm1nvp6ShNj9SQbyMF6PgSiZmCKHByJf3dujtZV" - "V1tOjhaF9fXUkc+bpEMfDxf89uL+AerpqtP0HCunTEBMdlxNx9CN6rPM3Nzf3y/gDR8ojJUC" - "6ln03dPVSK++NEjL87eyCf/jey0Lya0EH1ODF4iRZejHzPNMe2stra3y6DQKZBVBepQGAtY0" - "ROiVHz5C0aUZ+RP/a53GsIogPhcjE8NiJ4xim4VpcvB6ksuXL8sFQ7KSIK0JWXZ3ttGvfvai" - "/In/9W69sIIceH3QwYXz5y15bYslQSgOGhoZGZHnPRB1m315g5E9qri+taVJt/doNgzgCwj5" - "3NG3w8PUyfRhBSwJQvHeGBwnjFOn+KykU+sS7LiHg5syyBwOh/GWLfnIYqveo2PZCAHeGwNP" - "BbN4qEGcJHxXbPd0Mdj1ehYj6wK4LLx/wbnakBUtBgsgrHx/jqVjaygY3jyFgcS+vj7Z1YaZ" - "4fPvWk+ztbvV8TxLzffzABPE4FqYMqyFOM/6GJgyV795CuAFPHHihHTxwgV5XQLOHIMgWoIy" - "3trsAlc4n70sdS3WIyDwxhT9xMSELN/+/fvLUpvKXkWVbzucvXu35PUQ+sknnrD9hXo49E5L" - "0Njw//62QyX0CoB1CViqFCvjkcVKgBx05iDGzHx/OeC6+RzA6GYuI6i8m1onjHpSRvOqkKMD" - "Rg9KMoIKOTph5y43txIDuG6auoIVVMhxMSrkuBgVclyMCjkuhivJcWK6wY1wHTnKbZDlRv42" - "P7fBdXGOmW2QepG/zc9tcKX9MLoNUi/yt/k5LXc+XFcgDiPbIPUif5uf2/A/9n+1U7cLqMYA" - "AAAASUVORK5CYII=") - -#---------------------------------------------------------------------- -aero_dock_pane_left = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAYAAABQif3yAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzoyMTozMiArMDEwMExUiZ4AAAAHdElNRQfZAxkQKBW/8myz" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAD+tJREFUeNrtXWlsVNcV" - "Pm8Wz9iewTYYbxhjjDFmM4SloKwkipI0QiIhIU2VSlV+VVGrqlX6p5XaRpXa/kilVmqriD/N" - "IqWtQkjSJA2ozdJUQJMGEwwYAwZjDLaxjbHB23iW93q/O3PtWT1vmzevynzS9fO8eXOX893l" - "nHOXJ5ENMT09rfT09FBvby/NBAI5S6fY66XGxkZatGjRnoaGhnfzXW7bY2pqSnnr7beVSz09" - "SiAQUGRZzllA/EgH6fX19T2d77InQ8p3BpJx6vRpxe/z0YoVKyxL88qVKzQxOUltGzfaSh6O" - "fGcgGb2XL9OyZcssTbO+vp6nazfYjpzZYJBcLpelaSI9pGs32I6cAuZRIIdBUZR8ZyEtCuTY" - "GNZ27hpgVW2WJFspaAmwJTkgxsquxq4EfeXJQTpOpzPfRU6Lrzw5aDV2VQhsSQ5gV4FZCVuS" - "Y/WYY9eKUCDHxsg5Od0XLyrXBwdpdnaWxsfHKZvIh4eHeYhEIpYIQHI4yO1y8TQPvPnmgtmD" - "TldeXk4ej4dqamtpdXNzTtW8nJCzf//+1q3btnWNsAKHgkFau24dFbnd5PP5sv724MGDVFZW" - "RqFQKJflngM0Na/XS1VLl9ITe/dmfX5ycpLnbWhoiA4dOqQsraqibVu35oQk08k5deqUcvXa" - "NaqprqYtd9yhKw50aVa1HJGeWogKVlFRQa2trTQwMEB//+ADZXl9PbW1tZlKkqnknDhxQpmZ" - "maGHH3qIHA79niEQY1m3ZlCVrquro5qaGmpvb+fl37Jli2kEmeZb+/LLL5XikhLavn27IWIA" - "CEuWZUsCKoFR5QPlRblRfsjBLJmaQg5mL8PhMK1paTElU0JoWgPGD62/MVMzRPkhB8jDjPhM" - "IaefjTGbN282pYB6gdnTYEjWPItqtsoOOUAeZsAwOcfb25WNGzfm1T9VU1NLvX2D9If9B/gV" - "n/MFyAHygFyMxmWYnJGRET4o5gvQmm6OTdKrf/mUvCWV/IrPuJ8vQB6Qi1EYIufcuXPKqqam" - "vAkBBAzdCNArb7RTib96LuAz7ueTIMgF8jEShyFyrjNDbCkz3vIBv99P/UNhev9fg+T1VaUE" - "3Mf3eC4fqGRygdfBCAzZOZMTE1RcXGx5wUtLS2lorIjauybIW7wk43PtXbO0aY2P6ip93LK3" - "NI9Mrb59+7ahOAyRg+VEbrfb0kIDgUCAGmrLaUmFN+uzxeyRWzdvWZ5HyMXocitD5MAeMXuK" - "t8jj4fYHDDvEnw74fuzmdVUa4q3pzN4G5F3YRkjXbGTKv1rYbspgZWMjDbG+uq62lht0C9kh" - "agoPAjItUhROz/7+fmq0cPmvWtiOnA0bNtDb77zD3fjwWRUVFeUsLXiX4bjsOneOHn/ssXwX" - "PQWmkGO2lf3Ynj1wgdCRI0coMDubs8J7WVe2vKGBp2dmGczq6m3XcgTamJWN8FVGYcVnDmBW" - "KzTccgrz/akwq1vjsQwODv68u+fyC691hmlg0pj6lw21pRJ9a52T7t65I/dSMglnz56lK319" - "3L5SCwh2eGSEqqqqVP9GbINkShHnRWJWrPKNP50mpfVOum+nQqtKJILN72VfQ0+CJeGSov2f" - "lj4QFMO6CLNGBVMsyK4z7Hp5RqF/fiaRo+sY/e27X0v5HTSo02fOcMchVN1cL5WFmr1k8WKu" - "JabDu++9R5s2baJldXWaNEfkG2XQ4t4KMqO1n2mPHR0dtPfxxyXpkyPHlBdv7qBf3qeQj/Ht" - "dMTI4EGKXkWCGgqtiMD+RBSQpVBYjt4LsUh/+LFCzy86RvfeuTPhd0eOHqXKykpqXrXK8Iyq" - "GqAydHd38/+TCers7MRmXl1bIPWQIyC2QTpePh2i+nskKpKjtT3XiLBEXOzP2l0SvXo2MUX4" - "v7AGYf26dXz5EVwguQ4lJSW0evVqGrlxIyWvvUxIVm+BBMQ2SMcN1s1Usz7MyiEdaVV5JELa" - "QqEQIR/r/dFCIzFvRHwIMhvL6i2QgNgGWVClbQxeLVCT5bgrQnwNVmKftbYuJUMA5Ng/8Wp4" - "vhXyZJMgX/kR+eDkwH+IsSDCGHBi7HFElQA5lkMoBYqkQyFQoiQosTTwPzQ4KUupefdmow1N" - "eu04o/ZflBwlLkhR4c0N1bEmo1VUijLfUuRYfPwai1iZe05J/JFJBTNLmEaMbEVnOUTF5ORE" - "WAQhFhxytMVIjmgrigor2mQkjQTNdZNKNP5ip0RT7Aq7x0EKpfP2i4IYnQfRKoiFBCgWOIpn" - "EbLlTwhXiS1c1Jof8XtHVBhxLScmUEWOq+1K4nikJvCWEwtlbqbzX52hSsytSFHDNJM89NY2" - "vRBpKVm+BwJBB10ZCGa1v+I1Pj35SRhzImHiBqIzNuYgbUloAHo0AZrv1sqLJOrqHKaPPp+l" - "J79eS0WLnRRgbMtxmVlIIFZioW4Ntfnm7QgdPXGb2WJual1VlnU9t56KFj/Wxro1oqAcHfjh" - "rpn7OqYI8CtpVAjYDxpKJerrH6MDH/SQ01PN76MShCJxY0+accZqcjKmm9ICWNc8E6ZPPx+h" - "xWVOqqr0UzgcWihiQ2VxCIGFWW2OsL4sjO0XGBPmujmFjxmyhoAM1Xki1HXhKr3wm8PMoJqv" - "YTJLI6LMq9LpgH462SDMdViIOJEfgSAT2CtvfEF914ZZTXekLI4XceopR3xanBwIKyRHSYpQ" - "TLVW5v+PH3vUhMUeBw0MjtDPfvV6quApNubEtZz4jMULxIqQTERCSLknHoy2ipdf/5BGR8e5" - "RZ9cDiFkPflJIAfdDLo1BJAUUkRrigoyIshSEbxs4Dp78iQ994Nfp62JiB8NKZKGnHy0nPia" - "mq41JT6jULz6gFu//eOf6Xz35TktLpkYPfkR4GPOayMKLQmEqMIjURkbwH1MpYLq62EDkJt7" - "qSWuLDhUDjot6zfRS7/7MT3/01dTvuu5LdOVSZneY/WigShhjgQuc2QQnmKr1GloXkgP6SbP" - "1yAPuId8YbpAlotTavr3n3uaystKExYQgijECycughZgmkRog1GFgI1pE0xjK2Kf3JGo1ibF" - "lAHepUmkiZyu8QjdW7uUfvGTZ+jFl44kfDfLIpwOzysE8RC1B1qQVeRkG7DFXqF0+Xn2mQep" - "ckkZjY2NJcQjbCe9O/QSVGli5EwxgRWz4GWkFcXI4FzgOUeUILXkQH/5x3WiR1uW0ws/eoR+" - "/9r5ue/Qpc3ENDZR+HhBxAvECmTqUsR3uIf1c3PeaXbP7XLQU09t59ra0ND1FILnFivqLIfI" - "R4ycCCNHptKIgwIsriIn7B2FT7YJPlwayAEw/rxxOUQbFpfRvkebuJ3DyWHxTrO0QmlU6bnf" - "WrgnNJmMdHmZH0eISoudtGVLLbtKNDDQnzYeYavIOsoRb+BGyZFTFQA55gCN9xxogRxTEL4Y" - "CdP6+iW0IzBB5T4HjYxH5hyt/Lk0Lcfqg4mS04/7cq71YFzylUjU2lRMdUtl3pVlgnDB6ClH" - "iiqda3SOyVTc5KcDw2EamF5Yfc0n0qnSAiBndnqYmutly3YsWDLNN8Oa0H8YMbdCC7tqlOgN" - "SwqeDtm80tDagip3DphR0fK+4jPTlEHe82ID2IqcvAonXbeaZ7LyTk4ytIhDDLxGZk2h8oaY" - "qmzH0wqj5DisXTSNtIQo9LYcYUvAcocdohdhpupinZh/0SLbrCEQcFUyfb2UKVD+IoclBHlY" - "dfC7HTTBSl5RlKqgq20DIAdr244eO5a5+4mbtXSka10xdbeMEdOUZlc41rVl22VnJuJ32nlY" - "pXM9u9FNn5x0Uv097AYzTvyuqG+thAVvzLfm1uhbA2DjhGPebm+EeFweV3R9nJ9VCP8nRHvq" - "pzJmMltXBYHhDDdcH7j//oxW+pkzZ/jCwYaGhpTfw+r/6OOPqbY2/aESSysrVe+yS04bcYug" - "Fgk77RobydW2ds2H67/47MG/du6klTsUWsMMrXLGhJ+Rwv4ljxR157glbV0fJ4ZdZ5Wou2aS" - "XW8zknrYjdP/JWq99Rltf6At4TfIGPp/CC7bumQ8gxWZKDxqeLoxAxuvbty4QTt37ky76xuG" - "5PT0NG+B6YCVoNjAhV121dXVqtdKC3KCzDbCcl614DvtBgf5Trsn9u6NVs+bDMdPn6346zmZ" - "rk/ltvlWemR6dNk0rd+8kcrSNMVr167x8w1cKgZoLxM4CMWa5HTdDuJwM4Fm8gz7Skupigkd" - "LWQhXOjuplFGclDlAX2CnNHRUU27DFCWhuXLsXA+usvAiKBx7OKu++7T7BZXAzWCKMrDNns1" - "ADFoMYcOH6Z9Tz6pW8a2U6UF7Cp4K1FYK21j2LblXLx4kW/LUOvL0gMM8Bhvmpub813ctLAl" - "OdhAhUPltm7dmtNzCMROMqR391135bvYKbAdOdhlhlN1rXihHojHiSEwUJEuVGc7wXZjDroy" - "qw/Xw+61dDvb8g1DLQeGoFiqapZHGYaYmpOoAsyYnQpkT7OYWdEl3oW1WaRn5iHjQh5G97Qa" - "Isdj0OloBH2DAWrvnKCJqcxz9P5SJ7Wt8dH65hLL8iWWRYFsj8Hx0hA5Pr+fG6CwbK1ekNHS" - "WEwkB+nwv69mfGbXtuXU0pSdGLPnkUDO1NSUJtdNOhgiB0fij9+6RctKS00nR43AWprKyOUM" - "04H3O1K+27d7EzWtKFMVj5m76IRDdfTmTU2um7RxGflxa2urhDd8IDNmFlDL0tWmFUvo2ae2" - "0szE9bmAz7ivZjmsmRA+NWiB8CxDPkbiM6ytVdfU8GNEkCGzCNIiNBCwuMJH3/7mLgpMj/Ir" - "PqudfzGLoPjJP9hO8GIbhWFy8HqSS5cu8YyZeRyKlsXfSLKxoZa+9519/MqXEpu0BUQLOWLq" - "4sL586a8tsUUI3RFQwN1dXXR2rVrudVt9OUN6ZbGZgOer6mu1Kw9GjUDxMQgiIFidLKjI2Vi" - "Ty9MMULx3hgcJ9zb28snrsweg9RC7x5MvRBdGcqM2dbuixf5kcVmvUfHNA8B3hsDTQXHX6EG" - "CZJwT+sKGas2TulZFyDKIsYXzLCirGgxWMtg5vtzTPWtIWN48xQciS0tLVzVRjcj5t/VnmZr" - "dasTaWab7xcGJogR0+M4wPU8G2PQldn6zVOAyODx48eV7gsX+Am3ONYKBVFjlInWZhWEwMXs" - "ZbZnJyYmuOGNo/AHBwd5+Xbv3p2T2pTzKhr/tsOx8fGsz6PQjzz8sOUv1MOhd2qMxor/97cd" - "xkNrAbAuAYfhzebwyOJ4gBwM5iDGyHx/LmC7+RzAyp1thXdTa4ReTUpvWgVyNECPEaoXBXI0" - "Il/bDu0G201TFzCPAjk2RoEcG6NAjo1RIMfGsCU5djoZN5+wHTlYTiS2+uUaydv87Abb2TmN" - "K1fS0NAQX/UpjtrKFZK3+dkNtuw/Dr71lrK2tdWSF+phFx0mCLHNL9/lTobtMiTQ0dGh9F29" - "qumFQlqRvM3PbvgfnhklmOdyrPoAAAAASUVORK5CYII=") - -#---------------------------------------------------------------------- -aero_dock_pane_right = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAYAAABQif3yAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzoyMTozMiArMDEwMExUiZ4AAAAHdElNRQfZAxkQJBxqm5sb" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAD6VJREFUeNrtXVlsVNcZ" - "/mc89oztGWyDd8xgjDEGgx02BSVEkKRK8kCWkkWpIjVKX6pIbdVK6UP7UFWV2r60ah8aRbw0" - "SdUsDSFEJAW60SQCSlIMMXYwqwEb23gBY7zNfnu+O3PG1zN3PHebe2+V+dBhPHfuPcv/nfOf" - "/z/bdZANMTs7K/T19dG1a9doLhDIWTrFHg81NjbSkiVLnvT7/QetLrftMTMzI3xw4IBwpa9P" - "CAQCQiwWy1lA/EgH6fX39z9vddlT4bA6A6k4290t+LxeWrlypWlpXr9+naamp6l940ZbycNp" - "dQZSce3qVVq+fLmpaTY0NIjp2g22IycYCpHL5TI1TaSHdO0G25GTxzzy5DAIgmB1FmSRJ8fG" - "MFe5q4BZtdnhsJWBtgC2JAfEmKlq7ErQ154cpFNQUGB1kWXxtScHrcauBoEtyQHsKjAzYUty" - "zO5z7FoR8uTYGDkn59Lly8LN4WEKBoN0584dyiby0dFRMUSjUVME4HA6qdDlEtPc9/77i2YP" - "Nl15eTm53W6qraujNc3NOTXzckLO3r17W7ds3do7xgocDoVo3fr1VFRYSF6vN+uz+/fvp7Ky" - "MgqHw7ksdxKw1DweD1VXVdHTe/ZkvX96elrM28jICB0+fFioqq6mrVu25IQkw8k5e/asMHDj" - "BtXW1NDmTZs0xQGVZlbL4ekpBa9gFRUV1NraSkNDQ/TXQ4eEFQ0N1N7ebihJhpJz+vRpYW5u" - "jh595BFyOrWPDIEY09SaTlO6vr6eamtrqbOzUyz/5s2bDSPIsLG1M2fOCMUlJbRt2zZdxAAQ" - "ViwWMyWgEug1PlBelBvlhxyMkqkh5GD2MhKJ0NqWFkMyxYWmNqD/UPuMkZYhyg85QB5GxGcI" - "OYOsj7nnnnsMKaBWYPY0FI6pnkU12mSHHCAPI6CbnFOdncLGjRstHZ+qra2ja/3D9Ie9+8RP" - "fLcKkAPkAbnojUs3OWNjY2KnaBVgNd2emKY33/mUPCWV4ie+47pVgDwgF73QRc758+eF1U1N" - "lgkBBIyMB+iN9zqpxFeTDPiO61YSBLlAPnri0EXOTeaIVTHnzQr4fD4aHInQx58Mk8dbnRZw" - "Hb/jPitQyeSCUQc90OXnTE9NUXFxsekFLy0tpZGJIursnSJP8bKM93X2BqljrZfqK72iZ29q" - "HplZfffuXV1x6CIHy4kKCwtNLTQQCATIX1dOyyo8We8tZrdM3p40PY+Qi97lVrrIgT9i9BRv" - "kdst+h9w7BC/HPD7xO2biizEydnMow3IO/eNkK7RyJR/pbDdlMGqxkYaYbq6vq5OdOgW80OU" - "FB4EZFqkyAc9BwcHqdHE5b9KYTtyNmzYQAc+/FAcxseYVVFRUc7SwugyBi57z5+nbz71lNVF" - "T4Mh5BjtZT/15JMYAqFjx45RIBjMWeE9TJWt8PvF9Iwsg1Gq3nYth6OdedkIX2fkV3zmAEa1" - "Qt0tJz/fnw6j1Foylp6eHkHtNj94wGpHCGAdrWR6fv369SaJSj+Onfyc/nwuSsMzua2E9V4n" - "fbvNRZvaN4ozriI52HbX0dFBy+vrVVlHGNwDOWpaTog5ZoPMQurq6qInHn887XdYUN09PWLc" - "MHVzvVQWZvaypUtFK1EOT7z6BQmt99HO7QKtLnEQxkM8LEuQErwslyPeN6jpH+AAwPOKMLHB" - "TQ2xzzn2eXVOoH+cdJCz9wS9+52N5NCzzQ8CrKys1CQUbPXD8EZbW9uC68eOHxfjbF69WveM" - "qhKgMly6dEn8O5Wgz06cpN9O3ke/3CkQ6nGBM0GGGBzxz8S9aqqQwAP7LyqALIEisfi1MIv0" - "R0cF+nHF5+S0YpsfIG71YwRJgfEvrEFoYyoPy48wBJLrUFJSQmvWrKGx8fG0PL55LkYNDzio" - "KBav7blGlCXiYv+t2+Wg17vD5LRimx+ANEPMh+EGBQ9WrPdHC40mRiOkYZypmRqmw8w0d5BW" - "tdshpp03pW0My5xQsXbSQp/AaoNczrDBlZjkE8GR8rtDQ96FDAGIJf7QRY4eH2cxK0xUbzbZ" - "0ISxVfQFUZadAvQ9zrgRIPZBQtw4EBwaDAIhToKQSAN/w4JzSMSZJEeLkAWNzy2IQ/q8tBVZ" - "4NjKpRkTJMERF17SOEg0GbXVSBDmW0osEZ/4mYiY58LFM6Vl7kFgzyhtPeh0k50+axVyLYPH" - "o3ceRA2yrfiMst/CLDhZltysyZQwW3oO9q+QUGgJwtQQlFSTQjz+aMKkht/DpJQkySkVilqo" - "Ieb6UIgCIWfW54xojWrLwNOVFWRC5cC/qWY6bHxgjsoLHfO1XVjYHykJgpAeeFwRYV6BJMnR" - "FBQ8C2LOX5mk46fv0u270QUCSU1b7poZIVO6QDRCooNYVOCgm7eidPDoLbp4bowqipwLCNIT" - "opLACQR09Tmc4kzPulyFNDo+RZ9+PkTOwop0MmSEozkvOrBYuhBYKBYnCMM1k9MR2ndokL5f" - "WUgrl1dQ/4wQ78hVpCdtcYgXrQWf4Vg8njS1piUstkDc4XBS/41ReuO9/1IoMt+HKFGFMUlf" - "ZnbrSYUoPCbJmGSMIBiK0s9/c4R6Lw5QvTu+3jqmMuAf+hve+vB3RIjFW0+qWtOyQp8/l1pQ" - "eP+3bt2h19/657xpQly/ZlaL3BAwc5dBagtKU2tCvEZHZWyUn/3qLRoaHqOlzFJQo8aSVlqK" - "SuNGgWBUy0kVJKyfC5eu0u9efVtiGQvEu13pc6lpW9FyMuWFXwtHE2otQ+N6+Ye/pt4vvyQP" - "65OiMsKWC0lVxtVZQnWGovHAK4LY52AYP6RhjRUGKWdmZtLUQqO/nn7w8vP02h//llZTseaM" - "L1Xi3zmQB8SFkWKzzGkYLEgP6QZk5rL+NCbQskCYCdFFHc70nuW13/+EXJW1dHFS+WYvTlKY" - "NZ0gK2aAfZlhhsdkSCDGMX3E2oyfk6N1J5l0j4sUU1NTVLmsgl564Rv0l4PdC36TqsRU8BqL" - "OM0iJ1v/Fw2z8jDBBZCdlJHIX/z0Baqvq6JPRqOqhm+4+gqLxMTDLEtjJhonJCZtOVr3YEYT" - "m5zkBIm5Hn9DLb343DY68PeBpGWH+7EeTaoSOfjffPOUGZDr8xaAkYNaHYxS0rZ1FxXQK688" - "Rn5mrX08EBGvOVWYa5wcUZXF4nGLJLGoMGcUjkrI0SqMWIaWwzE0NCjujN55bx2d7g3Hna2U" - "liNrvpq4J1QK2XIwSc2wjiEUi48IlHld9PDDTTTlLaN3+kLkYqzwCTil4EYG4kQfE2QXoNow" - "8uBMmNRAsuVoGltbrMYlMDExQfVVS2g2WEzeYgcFZ8ML/By5lmPmopFUQyQNCR9nbE6g8ion" - "3dvhI1ruo5OjEXE4xykda1OITA4o0gHRUam1lmtghrO5IcaIGU2eL5BphMFKLJaXG7Mxevtm" - "hIpW+ah7wpxWbcrSKKioycnJjM8n/45fMKXg2fIih5tzMTo2IhDTbFTsyv2UhuUrPjNNGVie" - "FxvAEnKSQsgwtmYJbKBWU2F5y0mFGvHweSE9s6ZYGxdmpr0dTyt08UKaDdk1BCpqLt/4hEWQ" - "8Ju0IsL6Q6yh8y1ZIp++09wF5UiLVxOXmxUu204yIyHdTSa3ZVFpNUE8WNt2/MSJzH0Vu4eX" - "ySlXAROzoGWMmCaZXeEVRTEqZY/7ipymEORmTcVX6KQpVpxK5na4GletEo+nwt55PsakFBh9" - "RlBDKoiBULFpqSrDalElqgqVCWe44fOhBx9MyzevBD09PeLCQb/fn/Y88v6vo0eprk7+UIk9" - "K2bos54CanggSm7mlPiYheZlAVPVHla9mRypEOlocEL58I2HWeWIy+2Kr4/zMVJ8/yZxzbQL" - "b77Y/8EHgkvDTjJsbFrCap0abx4qaGh4mHp7e2nHjh0LfsMid+h/CC5bPnAPVowi32iBcn0G" - "8jc+Pk7bt2+X3fUNB3l2dlasLHLYtqmD2vpO0rtfbadV9wq0tsRB5YwJH9YSMDLcWDPtAEHq" - "VJ9IDPsMYo00I2iafWKSuI9d6P6CqHXyJG3t2DCvRbq6uoT+gQHZkdlMwC6DivJycYxNKXAo" - "3jLWYlrWrJH9/caNG+L5Bi4FHbSHCRyEYhxPrvUijkJGMkbP5eAtLaXqmpqMLRhAi/zPmW46" - "NFhC48HcKrfaUic93+qkbe1t4omIuiwBHLu4a+fOjIXXg5CCkwqLLNhmrwRozdAoh48coWef" - "eUazjG1nSnPYVfBmIr9W2sawbcu5fPmyuC1DywytUsDoQH/T3NxsdXFlYUtysIEKh8pt2bIl" - "p+cQ8F12SG/H/fdbXew02I4c7DLDqbpmvFAPxOPEEDioSHdNBgvSKtiuz4EqM/twPezsk9vZ" - "ZjV0tRy+ON3IN2lglELJSVQB5rDNBLKnWcw8xRLP4tYs0jPykHEuD717WnWR49Y56KgH/cMB" - "6vxqiqZmMo9O+EoLqH2tl9qaS0zLF4jhy63cOvtLXeR4fT7RAYWXbvaCjJbGYqJYiI58NpDx" - "nl1bV1BLU3ZijJ7HATlYzwdHVA90kYMj8e9MTtLy0lLDyVEisJamMnIVRGjfx11pvz27u4Oa" - "VpYpisfIKRM+oHrr9m2qrq7WF5eeh1tbWx14wwcyY2QB1SylbVq5jF56bgvNTd1MBnzHdSXL" - "eo0EP9sNViDOcIN89MSn21qrqa2l0bExMUNGEaRGaCBgaYWXXvzWLgrM3hI/8V3pNIZRBEkn" - "/+A71TCtohe6ycHrSa5cuSJmzMjjUNQsRkeSjf46+t53nxU/8d2oLSBqyOFTFxcvXDDktS2G" - "OKE4aAjzM+vWrRO9br0vb8i2UFEOuL+2plK19ajXDeATgyAGhtGXXV1pE3taYYgTivfG4Dhh" - "nDqFiSuj+yCl0LpqVSu4KkOZMdt66fJl8chio96jY9gIAd4bA0vl3LlzYg3iJOGa2hUyZm2c" - "0rJmgpeF9y+YYUVZ0WKwlsHI9+cYOraGjOHNUxhIbGlpEU1tqBl+yq3S02zNbnU8zWxnAHEH" - "E8Tw6XGshbjA+hioMlu/eQrgGTx16pRw6eJFcV0CzmRDQZQ4Zby1mQUucD57me1e7D2C440p" - "+uHhYbF8u3fvzkltynkVlb7tcOLOnaz3o9CPPfqo6S/UO/jRR4qcxor/97cdSqG2AFiXgMPw" - "gjk8slgKkIPOHMTome/PBWw3nwOYubMt/25qldBqSWlNK0+OCmhxQrUiT45KWLXt0G6w3TR1" - "HvPIk2Nj5MmxMfLk2Bh5cmwMW5Jjl5NxrYbtyJFug8w1pFsg9S5jygVs5+fo2QapFgteqNfY" - "aHXR02BL/YFtkOtaW015oR520WGC8Ok9e2wnC9tliEPLNki1QKvxr1hBHR0dtpTD/wDriTgZ" - "SBhbDwAAAABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -aero_dock_pane_top = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAGcAAABlCAYAAABQif3yAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzoyMTozMiArMDEwMExUiZ4AAAAHdElNRQfZAxkQKSNpU8hr" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAEFhJREFUeNrtXWlsXNUV" - "Pm8W22OPYzu24yXxEscxzk621kDaAGVTFVqxCoRaxJ9WlSr6j1+V2p+tVLX9U1URUlNVXdgK" - "EhRCgYKgSShtFpw4qx3I6iReEie2x57tvZ7vzVz7eebNzNtm3kPyJ109+828e885313Oucsb" - "iTyISCSiHDzyOf3peIKGp+SildMa9tH31wVoZXvbi21tbT9wW+9MSG4LkInp6Wnl8Rc/J2XN" - "nXRfn0JdIYlCfL+MJS3ja4Cvfr76DOancEoi8R8Jvkb5OsvXKU6DEYU+/UQi3xcHaPdj7S8x" - "QU+7rb8WAbcFyMR/j/STtKqPfnFHkqoUifxszYAPZPDfTIwkpWqUmVoFgtD+ZAVJoQSI4hvb" - "JYUeu8dHL8z00dD5z57ir3iKHKMVsGTYcyxOnTskKkumjFpMgKRgUqa6h1Lleg2eI2dsRqGm" - "ComKN9IsBMppDfnUcr0Gz5GziHl4bswBUJuVHAmQyFyXp+j8LcYhtbxSNVOT8GTLwcCtKGlC" - "cE0bT0kzZLYDUpSFSc7436vwZMsBGXE2mo+vki/loamMpK+Skr5nEHKa0KQiPLa0ay0vbEFe" - "gyfJgbsrswVlad6YPjajTCk/WnWlTdR4lQC1lShz+Qm3mtSy/G6rrAtvkiOn3Fw/SEmnpOZz" - "lRwTLUd0ZSIYVVtNOikWuslSwZPkoLtJLqjhCwNPswOldvyaD0ZTZah5erRf8yQ5MFxc03Ik" - "zXiDq3oxUd0XEJJulXE5lZBfwqNNx5PkJLj/iSdT82gQEC1lriuT0/9bcQjSLVJc0ULVLBdb" - "jnGkxgSFr0gStyApVfPF6CCZdwiSmi5NzRctSE5l4lFuik/O4NCQcvXKFYpGozQxMVFw8N1z" - "gY2WSNVqdezxpQyrOgWa6NNnsuVox5lk2jlIpLtM0XJefe21vOKhyNraWiovL6fmlhZa3d1d" - "1Fn9opCze/fu3q3btp0cHRmheCxGa9aupbJgkMLhcMFn9/z2E3rpukJN3K8tLZeoOihRlV+i" - "CvZ2y5iooC81O+03YRYxCx1jdqJ8neYbk3GiGzE45xL9jfPayd977NFHC+Y1NTVF8Xicrl27" - "Rnv37lUaly2jbVu3FoUkx8k5evSocvHSJWpuaqItmzdbymOWW84UG66cI1AI6FfdLYkUf8rj" - "MkOO6NJATpTJmeUmM8PkRNjjmI4paqwTjyeNZcYQFayuro56e3tpeHiY3n7nHaVtxQrauHGj" - "oyQ5Ss7hw4eVmZkZevCBB8jnsz4zFOVaHWGCKlm6crYbNx61GxNdGRwF2SQ58MxinFc0nWaS" - "qTJAdtI4N1lobW2l5uZmOnTokKr/li1bHCPIsbm1I0eOKKHKStq+fbstYlRwTZ7mqj7Do/Ys" - "J9T4WDKV4rL5pD7LA4varaXzRIpwGRG+2iFHNSLrC72hP+zglE0dIefosWNKgkfx23p6nJEq" - "keraoolUbVdTOi5BDyScBW2C9xXmJpaU9T9X3XNZ04I0ZZBNcgSgP+wAeziRnyPkXOYx5vbb" - "b3dGwzRkTVIKJHR33+0I0IrpS+rVJxV+Rpu/k4AdYA8nYJucg4cOKRs2bCC/353JQzgG326V" - "6PjJL+gnL/xaveJ/M96co/KwHWAP2MVuXrbJGR0dVQdFt7BxaYCuXJugn//yVaqsblWv+B/3" - "3QLsAbvYhS1yTp06pazq6nLNCJvrAzR58Sr97FfvU3Vdx1zC/7iPz90C7AL72MnDFjlXORBr" - "bGx0RfmeGj9dPzdOL77yBYVr27MS7uPz2/h7bvRwDWyXEQ7C7cBW1ZqanKRQKFRyxTurfRQd" - "jtAHn82oXVku4PNvJqepu62KTtxIlFTGKnarb926ZSsPW+REYzEKBoPOa+bL36SvRhS6t6uK" - "WpsqC2YVrpToo7HcvnKxNlHALrCPHdgiR+bATjIzd28ADSGJqhCzlPlyGm6Wg8qP2eAhA9LP" - "jKema/RQwc9XBX1UnS7Xacg21yI8t2Tw3PoAfXTMT8u/wcbnCh8OSBxcEoXYNy73pyY+A+m5" - "tYQB3bGVd0mZxMGnRBWyQuX8fNCnUJlfoUbmrIpJqd8r0fc2e84U3iNn51130LqDn9Kfj/fR" - "mq8ptLrSR7VMSpjJCLGhy/mKjjRgYm4NDSfGCZs6p5nQCU7XufWdmeUAeh9Rr/wf+taOO9xW" - "PQuOkKM4vPnr7ef76P1/H6CX35NpKFK8NeTVPB79tNdH9z9zp6M6ONXVe67lCNz/jTs5uS2F" - "u/Dkjs+vOpxqhbZbDgRxulv7qsOpbm0ul4GBAeXcuXM0Mztr+GFEwGZnCCoqKqijvZ3Wrl1b" - "IlPZx4kTJ+j8hQs0a8I2MOzI6CgtW7bM8DMhtk1nZyetX79eEnnQ62+8oWzatImWt7ZSWVmZ" - "4cwwuQdyzLScGAdml4eHqb+/n77z8MNZn2N9/tjAgJo3ZnidjqMyEQgEqH7pUhhE9/M333qL" - "rNgGcgv7WLHNo488IklYGKoOh6mjo8O0Yii8oaHBklHOnz+vTm+sW7duwf19+/ereXavWmV/" - "RdUAUBkGBwfVvzMJOn78OC1ZssSSbayQo7XN5NQU+c59+SUtX7686EbIxIoVK+gcC6EFdrZg" - "D8I67vKw/QhTIMVOlZWVtHr1ahodG8uSEfK5ZhvmJYD5HzTtUgNlxqLRBV0i/nZjBhktNJlI" - "ZHXPkM8t24CXRVfaw3AtCFVdcFoYE7jtkGe2HLfkEXLYIsdOjJPPC1O7tyJ7aWb1LOVzAnPk" - "WMlIsfhcTgUyxp9SQ69MOxXQqn1ExQwIAaysPSj8jFHhMeiK76JwvZYh8rG7DmLWEPnk19pG" - "yF1IPqEb7GNWF61tfFqjmIUZYs4Px2g25iv4nBOt0awOotx8nwOQH3oUir+EfpZ6I81zgcwb" - "pjKiwoZElH/q7E06fDJOO7++lFrqKct9zmeQUiJft4bafP1WkvYfvsWxWJB6V9VQssA+XisV" - "Tduj2BpzxBiR69lAIEgjY5P08WfD5AvWLVBWSZ9k1iOq1OTkLDerBUg0PZNgfUZpaY2fljVU" - "UyIRz5exLV3mujUrSU73qXpJknx04dII/fGV/1FMs55spJXKmrGsVCkfcUIeAegDvaAf9MzU" - "XWsfKzYVZfm0AphNuQRAhDs+PkF7/vLBgrPkipJRETIqhhg8rcpjJWUSkU++OX7SR7OhH/SE" - "vnqV1ooe2hZsu+VkCoA+8/Tgl/Sb3/1V4xkrJIbdzNqhV3tL2XJyyaK9N/+deT1EZYOe0Fd4" - "cYUqrhF5BNQxB1PVMQt7rDBJOT09ndUtdLa30vM/eop+/4d/ZtUMrImIgVT8P9ddsAyKetIs" - "XjJ3Gp4XykO5mes1Qj7IheUCWQ5l6QM9a2uqFmwgBFHIF/ZBMgM4UMIbVMmBsQp5HnoQz2WS" - "Mzk5SQ31dfTcM/fRy28ey1I4sw8XELUHeZaKHCPjXy55oF9DfQ3duHFjQT4idrJq1yxX2hI5" - "eQTHWkb7imZ69snt9MZ7F+c8O3wfB4y0TV9rCK1BSoFcXYr4DPcg79zsNN8LBnz0JOsFb+3a" - "tatZBIMctICkRT2EHAE7xpBztByB4eHLVFNTw/FNixrnKEp2y9F71mqNs4tcsszLjE2Iftqy" - "pUXdjAj99CBiFdmCHtoA114QmqPGaYEm39q4hCLREIVZoWgkviDO0Ws5pdw0kumIZHw4px/G" - "Jey77u0KsT6yqlcuiCkYK3pkudLFBlY4u1fITMyIqqQwSrar6u6igZ4rLQC5IT/0gD6lQEm2" - "RqFp37x5M+fzc3+nbpRE8UKy6Olnxqt1oqK5vuMz15KB67J4AK6QM2eEHHNrrkCvB3CZLNdb" - "TibMmEMMvHZWTeHyxtlVdus0eD4EhJKlhtYh0N4zChFLIHJHHGIVCR4PsU+sesmSrPLd7uQC" - "5awcBmz416WIyucCNC5T78ii0WqCfLC3bf+BA7m7H82qpU+vAqbd3RompkvnVDjkc8s24CXQ" - "uXKl+noqnJ0Xc0xGgagZyYzgKBxGxduWGnPsFjXSVcFgeIcbrvfec0/OKH1gYEDdONje3p71" - "PGT/14cfUktLi24ZkO/ayAi18ucJnX1t+YwsbGNm3xvkxV7yy5cvq3umAxs3bJD+/vrrCjLB" - "24/M7AeeZeNgu6qZKBhKDl+5QidPnqQdO3Ys+AyCof+H4QrJge9gRybkRg3XGzMg39jYGPX1" - "9eme+kYgGYlE1MqiB+wE3bdvHwW5jKamJsO2EeTEuLLDPkaBxqHa5tQpvPttvnr29/crFy5e" - "NLWTHqcM6mpr1Tkko8BL8eq5Rvaw4nq4dOmS+n6DgIEBuoINDkIxj6fXepFHkA2aa2Y4XFVF" - "y9jojQX2e58ZHKRxJjkWN/ZLIYKc8fFxU6cMoEt7Wxs2zs+fMrAKvHbx7p07TU+LG4ERQ5QV" - "45i9AwAxaDF7332Xnnj8ccs29pwrLeBVw5cSi3ulPQzPtpyhoSH1WIaVFVqjwACP8aa7u9tt" - "dXXhSXJwgAovldu6dasp79EsxEkylLfjrrvcVjsLniMHp8zwVl0rp8nMAsSv5HgCASrKXZ3D" - "g3QLnhtz0JWV+uV6OL2md7LNbdhqOWJzeqHN4GaAQMzIm6hmowpNzxYuM1QuUWVFfm8W5cUN" - "xjBGIOxh90yrLXLKbU462sGFK7N06PgkTU7nnp2orvLTxtvCtK678Ku/nILYFgWyy22Ol7bI" - "CVdXqwEoIttSb8jo6QwRyTF695OLOb9z97Y26ukqTIzT60ggB/v5zEzd6MEWOXgl/sTNm7S8" - "qspxcowYrKerhgL+BL36j/6sz57YtYm6OmoM5ePkkomYUB2/ft3U1I1uXnYe7u3tlfALHxDG" - "SQXNbF3t6qin557cSjOTV+cS/sd9I9thnYSYU4MXiJll2MdOfra9tabmZvU1IhDIKYLMGA0E" - "LK0L07NP302zkXH1iv+NLmM4RZB28Q+xE2ax7cI2Ofh5krNnz6qCOfk6FDObv1FkZ3sL/fiH" - "T6hX/O/UERAz5IilizOnTzvysy2OBKF40RDWZ9asWaNG3fl2gRolxuzKI77f3NRg2nu0GwaI" - "hUEQA8fo8/7+rIU9q3AkCMXvxlSxU4C3TmHhyukxyCis7lq1CtGVQWestg4ODamvLHbqd3Qc" - "myHA78bAU8Hrr1CDBEm4Z3aHTKkOTlnZFyB0EeMLVlihK1oM9jI4+fs5js6tQTD88hQmEnt6" - "elRXG92MWH83Ygy7W52sQJRZaL1fBJggRiyPYy/EaR5j0JV5+penACHgwYMHlcEzZ9R9CXit" - "FRQxEpSJ1lYqCIOL1ctC38XZIwTeWKK/wmEE9Nu1a1dRalPRq6j21w5vTEwU/D6UfujBBx2d" - "68oHseMFL70zEjTWfdV/7VALswpgXwJehgcySwGQg8EcxNhZ7y8GPLeeA5TyZJuTM+pOw7Pk" - "lOpMaK7zqV6AJ8mxEoRaxSI5JuHWsUOvwXPL1IuYxyI5HsYiOR7GIjkexiI5HoYnyfHSm3Hd" - "hOfI0R6DLDYyj/l5DZ6Lc+wcgzSLzGN+XoMn+w8cg1zT22v6GKRZgHycosMCIY75ua13Jjwn" - "kICVY5BmkXnMz2v4P+EM9joepX/9AAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -aero_down = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo1MTo0MyArMDEwMMndnrAAAAAHdElNRQfZAxkQNALaVrQp" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAhJJREFUeNrtl01v2kAQ" - "ht81FgECjUQUyeKjBrfi0EOJktxzg0uOSaWe0lNP/Wk99lBy7A+oSiO1ORE+BChSTjGfBuPs" - "rATCNSkmyHtpX2ll2czOs+OdWTMMXIPBwKnVaqjX6xiORghK0UgEuVwOhmEgFosx1u/3ncrV" - "FYrFItKpFMLhcGBwy7LQ7nRQrVZRLpXAfl5fO4l4HLquBwb9U41GA2avB6V+e4t0Oi0NTMpk" - "MiCuOuavQlXVtRNGFs+NobPWLhphiO783YZ4gut3tc3OEN9/9fDQt5+0ebEbwttCHG9eR335" - "9A0v5LhDx0LlW+tJm6OTLAr59WDHcTaDiwXk96AqNj5/+eH57fzsEIa+t4k7KMur8TMMPYkP" - "744xMO8Wg+7puZ/5HrhfMI3ZbIb9ZByX708xHt6LK93Tc78+XHu+alXrlNdT+PTxgpepBtu2" - "fc8nu1AotB18Op1C0w7EdRMxxrwJtyn8uXOW9ezIt5ErctlwT+SUrTKkKIo7cvrUTSYTKXDK" - "dEo6V+RULrLkipxeuSy4p9QILmvP5yfhAi4z4VbCZZXaMkfZws/W+g//R+Hz4046fIe3R3S6" - "0YEftChIOtuJR1zRLvHiQ4r3afRxCbLeCRzhzWK73Rb/gNRXvGP8WqmILkLTtEAbRQqu0+3i" - "980NyuUyxGabpila5GarhVGALTJF/TKbFS1yIpFgj6VqglrJraorAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -aero_down_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo1NDo1OSArMDEwMEcuCiQAAAAHdElNRQfZAxkQNxVyqGIt" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAABENJREFUeNrtV02IHEUU" - "/qq6529nFnezLtGNEEk0O5NZI4GoQaLxoCJ4NgjBgAe9K/5c9SToQbx6UaJgQLyJXgIRDUkk" - "t+iS1YDgwSWHMGOyO7Mz0z/l97qqZ3vGnd0ZYb1oDY9XXT39vve+eu9VtwJHo9H4+ufrK8+f" - "XQ6xuh5jt8ZCReNM3Ue9uvjl3NzcKUXgH06fvX7C1B7H08cNDpQUSvxjXlGofWqPWo8JYCiR" - "CCchdZe6Q71OudE2uPy9gv7tEj57qXpeXbh4yXzQfAzvnTQoGwWPKL4WMM4JrERgZdwhDgh/" - "sRExCMURLhjOu1rjrW8M3tz3I/QnPwW4/4RCPrIPjRpaWad2Er2Nl+JELoox+xwguP6tDYOD" - "RYW4sz1wnjzeaW3nnh2VKQXDvYpH/FUYWShpLBPXH4fGPCNaudHC+ctNNG6HI/+35y4fTx6b" - "wZGlaYTRznb91BszQmR0aKhWrUDo+fSrX0YaO/XsImqHp9HK+GcyOq2jOM6CG0kGByhabmo7" - "ly1kHqJNg/X6PF7xAnz48Xd/A37t1adwqDqP9cAM2jIZ+0NbkVSQgAUuI6VE0lLpZ2xs9Z2e" - "waHFBbz7xjNYa/7eF7mWdbkfG/QlGpqL/SDeZEDbyPlQbKx2YuhRMocTt367F+PevTN45+0X" - "0F5bTbRcy3r/WQzZyNplJIO0x7YMPIp2ks2XpM4zJXQr9FCvHcBH77+OBw7ux83OYJmmVKcM" - "JlE7SbekD57SnaUs21iGu5s8vLoBzNy3P9HDI7vnm83GYqg0w7MJF2QiV8YhO52oLep2Y0Q5" - "DQA6VgO332IvNNnIaSSIbB/3XaR9qmN3PUF/jV3kUZrA8WbCqeFSs3tiqEXY043tUHG6O2rr" - "yEcNM1QtiV1hwLW9NNtt5KH1Ktl7bR9Mki6lHtv37K0iz+5zWr6h29KByM81DPaS9z0Fhemc" - "QpnHWdGzbTWn7enmTQCenmI9onepW1xYC4Amy1Hx9wVtnUzBO4x8nTcKSicLXpKuPCA8m7GT" - "gKeUC3iX4NKaNwjeZka3erbWgyDajLwb2PY5xasC1xl8QnNKtSRiPCG4ZHaPtrpOpDIEQ4KJ" - "ogztkuotulrmYpEbnReqo836NhOCJ22UKD2JPpLorbRDY50bAA8t9V1Kj1T3tHt9cm8xySEz" - "IXjax/sMOIxkDIDDlQV2Pl7HAd9KUtvZMe574a6M/8H/q+D63/Mii+Pfzc+jMmugwka+2w4U" - "WdjlnMY054Lrv/xQDheuedj3RIQSi7/C7lLJASV2mIJnDxb/H/T2gC2xyN5e4PM5HpF5vqnM" - "c71M0LlvFc4c9eEfXTq8Ur96pfr58nHUHjV4cEpjhqAVgvHDgocNHYDteOOCy6nGMwT8KEGL" - "rP5JadCjX/mu98dFoBpfwbGHl2z3bDab5uq1ZZxbiXGztXufyPeUNV6sajxypI7Z2Vn1F7X+" - "m7ZM/KBNAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -aero_down_focus_single = aero_down_focus - -#---------------------------------------------------------------------- -aero_down_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo1MTo0MyArMDEwMMndnrAAAAAHdElNRQfZAxkQNALaVrQp" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAhJJREFUeNrtl01v2kAQ" - "ht81FgECjUQUyeKjBrfi0EOJktxzg0uOSaWe0lNP/Wk99lBy7A+oSiO1ORE+BChSTjGfBuPs" - "rATCNSkmyHtpX2ll2czOs+OdWTMMXIPBwKnVaqjX6xiORghK0UgEuVwOhmEgFosx1u/3ncrV" - "FYrFItKpFMLhcGBwy7LQ7nRQrVZRLpXAfl5fO4l4HLquBwb9U41GA2avB6V+e4t0Oi0NTMpk" - "MiCuOuavQlXVtRNGFs+NobPWLhphiO783YZ4gut3tc3OEN9/9fDQt5+0ebEbwttCHG9eR335" - "9A0v5LhDx0LlW+tJm6OTLAr59WDHcTaDiwXk96AqNj5/+eH57fzsEIa+t4k7KMur8TMMPYkP" - "744xMO8Wg+7puZ/5HrhfMI3ZbIb9ZByX708xHt6LK93Tc78+XHu+alXrlNdT+PTxgpepBtu2" - "fc8nu1AotB18Op1C0w7EdRMxxrwJtyn8uXOW9ezIt5ErctlwT+SUrTKkKIo7cvrUTSYTKXDK" - "dEo6V+RULrLkipxeuSy4p9QILmvP5yfhAi4z4VbCZZXaMkfZws/W+g//R+Hz4046fIe3R3S6" - "0YEftChIOtuJR1zRLvHiQ4r3afRxCbLeCRzhzWK73Rb/gNRXvGP8WqmILkLTtEAbRQqu0+3i" - "980NyuUyxGabpila5GarhVGALTJF/TKbFS1yIpFgj6VqglrJraorAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -aero_left = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo0NDo0MCArMDEwMN+SkKkAAAAHdElNRQfZAxkQMBKjjWFJ" - "AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAABGdBTUEAALGPC/xhBQAAAkJJREFUeNrtV02P0lAU" - "PS2lUEIlkxlHpCAEZ89Ol27M8A/czMK4duO/caeJiSZu3SgTN25M3DhBFkMmDhQJEK0apnwM" - "0wK1t+Z1YOqyr2w8yWuT95qcc9+97/UeAS6m06nTarWg6zrOZzPwhJJMolQqoVwuI5VKCcJk" - "MnFqh4eoVCrQcjnIssxVgGVZ6PX7qNfrqO7vQ/jSaDhqOo1isciV+Co6nQ5G4zFEvd2GpmmR" - "khPy+TyIW7xwt0SSpMgFECdxi5EzX8HGBDiOs1kBDH7ymaKoIAjCpQAiXy6XXAlFUfR4aBA5" - "EyBGET2R630LM+tvxpmQNQG8BpE3T8/w8cjEb3MREMe1BuLxOL4bY3z4NIAob/nzq1x+DYQt" - "IBaLodM18PpNA0p6Fwn5kpzqjXZmTUCYRUiR//x1hucv3yOl3lhbY4Gyd+g7QJGffG3jxau3" - "SCg7gXUWLH3nC6BfJI2wUC4V8OTxAZ4+qwXWiGexWPgp8J40EeYwTRM72xk8OrgfEMC+CRzD" - "sEUYhoFi4ToePriDuBTzBdD20zqrOWl1Mmz0ej1kMhncu3sTn5u2XwORHEOG4XAIbfcazm0F" - "aUXExdQO3oS8MXZbrz1t6ZL/gG3ba2uRtEKUYirMf2Hj/cB/AZ4A1hxsREDCdUKrVyNvULD0" - "HyBO4vackXsokXNtGR0R3t0RkSddf0iX1Hw+h3TbNYnvajXPKGSzWe7ekILsDwY4bjZRrVbh" - "JX80Gnnu+Fu3ixlnd0zR3yoUPHesqqrwB18A5ik1mQXQAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -aero_left_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo0NjozNCArMDEwMCXtbZ4AAAAHdElNRQfZAxkQLw561jOY" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAABAVJREFUeNrtV02IHEUY" - "fVXTO70/M+yOExNd4oIRkgljDIiyQZR4FD0rQlDw6E1RDwkoIqiHXLzlKK4Iwb2peFDJHgxx" - "dS+LcTMhhw0qJkvG7Jjsz8xOd1f5qqu6p9eNMB2Y9WLBm6+nf+p79X2vvqoSYFtdXf3ql8bl" - "52aWQlxbVxhkmyxJvFz3UK8dmq1Wqy8IOv/+xEzjSV17AsePaTw0KjDCF4cFUKQtEB6vJSz6" - "bWYYERFqoEvbpW3TXm1rfDsvIBsX8OlLte/E3PkL+vTqNN4/rlGCQEE6hzGEta5TkYOATsCf" - "SBtCGqGy9wJ2+vo5jbcqP0J+fDHA/qcEisqyHnSL6MTjz+GnBYxv+SdDso/x1rvgPBudvb6A" - "8Z0nrQNpXsJIZaxBNt/a/c8bJf0vME3pDAGlbG4ieikYLUgrPOV6MULU4i5EqK0j7XyYazMz" - "RGYkXsImhbAvpIJ0Q8/jHM55MmLl+out6hFMCUR8OyCksiMX0kYj7gV26CInCZVxbvofKQhs" - "0Jq6IPkkISKTFKQRcB9plWGtt+ujH8QRcBgfEmj+3sYe1hVTY0J3PyUQhYiLhHkQa8Hlalvo" - "7hITRYErl5r44txNrNyMUGQkEpKZFLBUKiu2AjKhduKLLXKKkB9MjQn89kcLs18vo+Dvi++b" - "gQZRTwtecjMk3UiaHAlb97VlGidfO2306dy8N+krNK5cx+kz51GamMKo77TB3Ea6Nw1lEoFA" - "WSKR00SaBpU/Dff4EteuN/HOB5/dUZyh01hKwITEpMDAEAl0EpV/6KIPDDPHlxYX8eprH94x" - "Oqb/bmT7TFMw09SodgJUWJ/HKZoSpWqmjU9BDMWrI1dJt0L20w7Wj+LMRyfxxtuf7Hi2fFvh" - "V+45vuTYp9IUBMAaZ8IGmW0SbaKjLLZULzr9ovFXhMn778V7p07sIGD62wyxvQ6ABDZC+6BD" - "bEUWXYdA5UOH33yzAhw++ADeffMZ+MVCSsD013YzIUMgIgHFkWt+TFBJW6TYpQ2IxOaB6efz" - "qwHWS+N4/tkDGC95lgCfbdJXkNUA1E7RKbcoZStknqacKBeaIer7q5jurGGC+8Em05Msfr0I" - "DLgttRRGDpQxe4Ob3s3tQ/F2g4BJ7Q90fivYuaP4z3dE/xOQye9uMjG+ksrg7RkRGKMwy0W5" - "KyR8yr7M+r5GPRrf3itHhjC3WODhJILPyVv27FowSgy7tWAo51pgmqkBoVtlhyPEffmePX+U" - "6bg8h/iM6D16pH6jvjC/9+zSMTw4rXGIZ8MJeivTMS/hmzOiMCTypSl2Trulbeldp71NIsu8" - "cfEnoHZrHo8dfdjuMVqtll74eQlnLyusbAz2gHbfmMSLNYnHH6mjUqmIvwGdqbciWIcx6wAA" - "AABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -aero_left_focus_single = aero_left_focus - -#---------------------------------------------------------------------- -aero_left_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo0NDo0MCArMDEwMN+SkKkAAAAHdElNRQfZAxkQMBKjjWFJ" - "AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAABGdBTUEAALGPC/xhBQAAAkJJREFUeNrtV02P0lAU" - "PS2lUEIlkxlHpCAEZ89Ol27M8A/czMK4duO/caeJiSZu3SgTN25M3DhBFkMmDhQJEK0apnwM" - "0wK1t+Z1YOqyr2w8yWuT95qcc9+97/UeAS6m06nTarWg6zrOZzPwhJJMolQqoVwuI5VKCcJk" - "MnFqh4eoVCrQcjnIssxVgGVZ6PX7qNfrqO7vQ/jSaDhqOo1isciV+Co6nQ5G4zFEvd2GpmmR" - "khPy+TyIW7xwt0SSpMgFECdxi5EzX8HGBDiOs1kBDH7ymaKoIAjCpQAiXy6XXAlFUfR4aBA5" - "EyBGET2R630LM+tvxpmQNQG8BpE3T8/w8cjEb3MREMe1BuLxOL4bY3z4NIAob/nzq1x+DYQt" - "IBaLodM18PpNA0p6Fwn5kpzqjXZmTUCYRUiR//x1hucv3yOl3lhbY4Gyd+g7QJGffG3jxau3" - "SCg7gXUWLH3nC6BfJI2wUC4V8OTxAZ4+qwXWiGexWPgp8J40EeYwTRM72xk8OrgfEMC+CRzD" - "sEUYhoFi4ToePriDuBTzBdD20zqrOWl1Mmz0ej1kMhncu3sTn5u2XwORHEOG4XAIbfcazm0F" - "aUXExdQO3oS8MXZbrz1t6ZL/gG3ba2uRtEKUYirMf2Hj/cB/AZ4A1hxsREDCdUKrVyNvULD0" - "HyBO4vackXsokXNtGR0R3t0RkSddf0iX1Hw+h3TbNYnvajXPKGSzWe7ekILsDwY4bjZRrVbh" - "JX80Gnnu+Fu3ixlnd0zR3yoUPHesqqrwB18A5ik1mQXQAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -aero_right = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo0NToxOCArMDEwMEtfu5QAAAAHdElNRQfZAxkQLyM/CW/t" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAkpJREFUeNrtVz2PEkEY" - "fnbZQ+AgGD+R5YSAxVkRLfwF5vgH11xlbeNPsbE2Ftf4C+RiY2OijeGu8GIusEjgiJ4Ej689" - "YHedd8zgsBgt3Fkan+TNZnY3eZ55v2ZeDQzj8dir1+uwLAsT24ZKxGMxFAoFFItFJBIJTRuN" - "Rl714ADlchlmNotoNKpUwHQ6RbvTQa1WQ2VnB9rh0ZGXSiaRz+eVEvvRbDYxGA6hW40GTNMM" - "lZyQy+VA3PoFc4lhGKELIE7i1kNn9mFtAjzPW68AgUXwhaKwoGnaLwFE7rru4gOZWKsiFwJ0" - "/+7tqQ6rw7JTVxcd4hOchvyCVPXOHbz9cA57soHtUhqO4yjxgMBSDogPo4mDN+/OcCVt4Ob1" - "JGazmTJvLEIgu4Uwmzt48fI9mq2vPBzyP/9qlF9LZeh/KeP5/mucffuOSCTC/wnCBOcfPSDj" - "6bN9fDppBOYJucJ4DtARSfbzKI6vCHjyeA+X05sYstMrCJA3RZVxAZTpwvx4tPcQ166m0ev1" - "Ak2+lTIkctk1G0YEu7sPeBV0u91AyQmCyxALEiBUbcYjuH/vFnsC7XY7cHK5yS01Iqr3ZELH" - "3VIc5g0X/X4/cHKx4d+ehiTgYvwFd0w3sIT7G1auQiRCZefzY+33gf8CuAD5eAxdwCXWfqkH" - "qLyAyKDNUismTuLmkxErSmTZWEbZr/puSOQxNh9Sg5vP5zBKbEh8Va3yQSGTySifDWmTndNT" - "fDw+RqVSAQ/+YDDg0/HnVgu24umYdn97a4tPx6lUSvsBjEDOU65zEi4AAAAASUVORK5CYII=") - -#---------------------------------------------------------------------- -aero_right_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo0ODo0NiArMDEwMKZ+RR0AAAAHdElNRQfZAxkQMQU5RdXP" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAA/ZJREFUeNrtV09oVEcY" - "/83sy27UfZhtNLWxKNaDK6sNlJZIabHgpdB7KYiCR28W7EEPIkLbgz1481hIaSt4a6UUWkyh" - "Imm9hKbpSg7pIUVjotnGJG5235uZft+bmc1bk8A+NTn1W743b98bvt9vvn9vRoBkbm7uxp/V" - "ux8Mjce4t6ixkdJflDhZCVApH7je29v7oSDwX48PVd8x5bdx9IjB/q0CW2hitwDyNOZIA7qX" - "sNqp8DIUaWyAJo1NGus0/l03+GlEQFZv46sT5Z/F8K3b5vLcID49alCEQE46wESFHZ1RkYGA" - "8UoXZZiQQazts4iMfnzT4JPSb5BfjkV49V2BvLasN1oUgQR0OfieAGPLh+SSl8nfZhPA097p" - "KwgwdpawbogEnpFOjazpeBv3P6uXzDrKok2KgNY2NopQcpwL0iaedlY4EY14hiQ0Fsg4DL7n" - "yhCplQSeTUuFndBKSLf0LOBw4H7F2tlLRr1CsEVA0eyIVNLLAi19K9VhnWvHOOc7UllI6BQ4" - "21euHLkvSHrjiUgfAp7I9d9H/n44VUdPl1hhbdrzoxM1ZrV6W7FfmyegYiRNIp8TmH6k8N3N" - "R5j4axalvGwj8TyqUupJrhDgdqktCZb5xRjXf5jEvw9q2EutudXNMgKyPT96jVgV2kNgX1Jc" - "Ur2w0VS4+MWPqE5Mob+giAS9z6j84/jrVC7ERrcW0+aByJXi03Lhs69x7/4sXqLszOIBg7Xd" - "7xPRpD3ALklCsE6nOX3mc1RHR9FNOaLWMLiWxs5e7O4jF+amsuoXm5Th0KxB73JEEwMMyNXF" - "dvXKOQQ7dmFiXnVchp5IRC5oENgy/VmiZJ+n7zKtA9/T2ve0+kAELNDLZY1VH/1L54+j/5Wd" - "+GVGZWrF3tVRAm71CWEsKQuq0x4AEWB2DdV6gkI+h7Nn38ee3SXcmIptvDJ0Ik8gcbu2thMi" - "ZIr3HJFqI6CIgKaJtvNtLwY4duw1LBS349vJJgJC9puULASiBNwkMW/QAw4Dd1jpynGFgKvR" - "Wfo+9+yUGBwIgd0hRmbipDXL9LehQ1mvCTEOL0alq8DLP080vpmOkd8XYqzWecI9j6zakEzX" - "NW49iFGPs6TcCySw2fI/Aemvm8mEsXLuPtixRWAblURI3/7NIFGgwg+7JBYoxxk7OHW4C8Oj" - "OTqcKBSoaEMq0iIpb8u6iSbNRRedkHLP0Ih8K+6mimZbhcCeP0ICDoeRnBGDNw5XZip3Rvqu" - "jR/BvkGDA7QB6SG0kPeGBFjgM6JgEtnClIDT2OAzIZFYpPExEZmkB2O/A+X5Ebw5cMjuM2u1" - "mrnzxziu3dWYXtrYA9qubRIflSXeer2CUqkk/gNN/sDRnOMoBAAAAABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -aero_right_focus_single = aero_right_focus - -#---------------------------------------------------------------------- -aero_right_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAYAAACGVs+MAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo0NToxOCArMDEwMEtfu5QAAAAHdElNRQfZAxkQLyM/CW/t" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAkpJREFUeNrtVz2PEkEY" - "fnbZQ+AgGD+R5YSAxVkRLfwF5vgH11xlbeNPsbE2Ftf4C+RiY2OijeGu8GIusEjgiJ4Ej689" - "YHedd8zgsBgt3Fkan+TNZnY3eZ55v2ZeDQzj8dir1+uwLAsT24ZKxGMxFAoFFItFJBIJTRuN" - "Rl714ADlchlmNotoNKpUwHQ6RbvTQa1WQ2VnB9rh0ZGXSiaRz+eVEvvRbDYxGA6hW40GTNMM" - "lZyQy+VA3PoFc4lhGKELIE7i1kNn9mFtAjzPW68AgUXwhaKwoGnaLwFE7rru4gOZWKsiFwJ0" - "/+7tqQ6rw7JTVxcd4hOchvyCVPXOHbz9cA57soHtUhqO4yjxgMBSDogPo4mDN+/OcCVt4Ob1" - "JGazmTJvLEIgu4Uwmzt48fI9mq2vPBzyP/9qlF9LZeh/KeP5/mucffuOSCTC/wnCBOcfPSDj" - "6bN9fDppBOYJucJ4DtARSfbzKI6vCHjyeA+X05sYstMrCJA3RZVxAZTpwvx4tPcQ166m0ev1" - "Ak2+lTIkctk1G0YEu7sPeBV0u91AyQmCyxALEiBUbcYjuH/vFnsC7XY7cHK5yS01Iqr3ZELH" - "3VIc5g0X/X4/cHKx4d+ehiTgYvwFd0w3sIT7G1auQiRCZefzY+33gf8CuAD5eAxdwCXWfqkH" - "qLyAyKDNUismTuLmkxErSmTZWEbZr/puSOQxNh9Sg5vP5zBKbEh8Va3yQSGTySifDWmTndNT" - "fDw+RqVSAQ/+YDDg0/HnVgu24umYdn97a4tPx6lUSvsBjEDOU65zEi4AAAAASUVORK5CYII=") - -#---------------------------------------------------------------------- -aero_tab = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAMAAACxiD++AAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFq6ysra6urq+vr7CwsLGxsbKysrOzs7S0tLS0tLW1tba2tre3t7i4uLm5uru7vL29" - "v8DAwMDAwsPDxMXFxsbGycrKzc3Nzc7Ozs/P09TU19fX2dnZ2tra29vb3Nzc3N3d3t7e4ODg" - "4uLi4+Pj4+Tk5OTk5OXl5ubm5+fn6Ojo6enp6+vr7Ozs7e3t7e7u7+/v8fHx8vLy8/Pz9PT0" - "9fX19vb29vf3+Pj4+fn5+vr6+/v7/Pz8/f39/v7+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAA0PbvAwAAABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjM2" - "qefiJQAAAP9JREFUOE+t0tlSwjAUgOFjZQuxuOBSFURSSOyq0qYNEd//tUzCaIeLk9743Zyb" - "f5LOSUH3AC3vyEWIuIw06KvHRmGqKIJ3+u1RzaD0BpL+S3DwfIO5oqAHDxPk1LOpr9oGe0/h" - "ArXHmSCjLbpIpSobyBa3o5DSWqJaF+xqlPykEE/LHFWmU2AkS1GZCdYkFajkjZhAxCghCLwS" - "zlCcE1j1BpOeE176gqU/mMBy3F0Rb/mpZENh0QWxyJNTfD6HRXfFthgNndFgcJzDa2aCv0WZ" - "tUj7blLdP9nZ6PCZATtPft+qjELt/vAm/HCzCNYmuA2O5xqzmzOwAuIG0AfGfgDFvqY+8bKe" - "lgAAAABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -aero_tab_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAIAAAAJNFjbAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "ABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjM2qefiJQAABPtJREFUSEu9ldtPI2UYxovR" - "jZd65Z3xxv/AO2/0wnihiZpodgV21cSsiyYbs8ZkiQQSDUaynBaIB0ACLOsegJaWlkNpObSW" - "XQ5dlgUqPQ3DtPRIW9pO5/DNtPGZFjeVte2F4uTtxcz3e96n7/t+802VJEkqlapx2LQXE589" - "80xVVRVu//319FO5F587c/Xc6yoYXOrW983vzrqOrExqPcBuRTLOQ94T5/cSApMU/EnxIFUh" - "wIAEDxW0jyKZRSr+Vv3d724YFYPaDn2Iyy5H5I2Y/MeR7EllaTbrz2QDXC7E5yJ8LlopwIAE" - "DxW0yOBOylOO8CedOlUikfio0wAD239tYPEkatu0qng8/j8ZWCPyg5i8cyS78y3y/dWicL5L" - "5QNMoUVQQYsMzqR8XEEsHr/QaQhksosheS0qbyVkZzJLpbP7yhgUTYjLQV8+wOQHkIMKWmTA" - "LJcKLSoYYDimgHw/Ij9U5qxMiU5nGTZ3AI+M4lE+wIAEDxW0yLCdkBeODWIxGDCsPOUn1jBZ" - "P5TyRcjelEynZaawnSoFGJDgoYIWGTZjktkTUyo4PDw832nA2iRDFoNkNSptxpXNin1GpeX9" - "dNaX9ygfYECChwpaZNiISXPuWM1jAyolj9NkLkCWIxJGjQLxRzwpeS9d6FWFAAMSPFTQIsPa" - "oTRbbADnmx5iYMhSUFqJKpPYgQdeOgw8P4/yAQYkeKigRYZ7EWnala8gGo2iRVgbdAvafdGc" - "L8KOSaBRCdmFOtCrVIUAAxI8VNAigzVE9LtFBljrdQpjtDjrJ5aQhEngj6BYNLTgUT6U7EcK" - "DxW0yLAQJLqCQTgcru00bMXk6zvCTY+oY4g5INnC0nq+Udv5OlBf+QADEjxU0CKD0U/UO48N" - "Ogy2kPTGdPKilW20cx3b/K9O4bZXnKDFKYYANR+Q+dKBVTAgwUMFLTK0bPENJqamVavy+Xy1" - "7YbFgPSKNnl2gb2ywjVv8j0OYdAl3qZEDU30DJn2kZnSgVUwIMFDBS0yNG3wXxvzBgzD1LQb" - "5vzSy2PJt43sJRvXYOdbt4RfdsVht3iXUpS6fTJZOrAKBiR4qKBFhqtr/JUZprp1QkXTdE27" - "Hv/ihd8SrxlSF5bYr1YzzQ+5rh2+3ymMeIQ7XnF8T1SXDqyCAQkeKmiR4fI9rq7YAG/A8yOJ" - "VydT1Qvsl/cz325wndt8764w7BJuecRRShwrHVgFAxI8VNAiw+c27jNDvgKKolDBKRp4vd7T" - "NfCcuoHHc0oV1GEG1yZUbrf7w7YKM8A+0dGifp/8Y2AHT9BklCI33GLvrti+JTTa+QY7V6dz" - "fdyhrWyALYhNvIrzi8mUiqX9zDzNGilW706P7aZGHMn+9eC7Tepv+iZVLperfIvUlLgWlc61" - "6j5o0TwZ7/+gQTz5vLZVU//zxO82m2JQ3aaf9ZGX7iTenEl9amXr1zMtj7gfHfwgXgKvoHwk" - "9pK1rdp0Op0qunDL87zJZFpZWSl+zrKsKIqDQ0MWiwXHhGLw3vdqq5//YjnTZOe6d/ght/Lq" - "4vAyHSjfHxyQP5kcl7vVhJDc3680yw4NDeGje+J5MBjs6u52OByKAX5N/bp3mtVnr2lLxcUu" - "3a1R9fWurvaOjuLo7unp6+8/8RC3AwMDJrMZh9CxwfLyslqj0ZW+jHNzFqt1XK0eHRsrDo1G" - "ozcYTjzE7fT0tP3BA2TH9Sf2aVnapn4zWAAAAABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -aero_tab_focus_single = aero_tab_focus - -#---------------------------------------------------------------------- -aero_tab_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACAAAAAfCAMAAACxiD++AAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFq6ysra6urq+vr7CwsLGxsbKysrOzs7S0tLS0tLW1tba2tre3t7i4uLm5uru7vL29" - "v8DAwMDAwsPDxMXFxsbGycrKzc3Nzc7Ozs/P09TU19fX2dnZ2tra29vb3Nzc3N3d3t7e4ODg" - "4uLi4+Pj4+Tk5OTk5OXl5ubm5+fn6Ojo6enp6+vr7Ozs7e3t7e7u7+/v8fHx8vLy8/Pz9PT0" - "9fX19vb29vf3+Pj4+fn5+vr6+/v7/Pz8/f39/v7+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAA0PbvAwAAABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjM2" - "qefiJQAAAP9JREFUOE+t0tlSwjAUgOFjZQuxuOBSFURSSOyq0qYNEd//tUzCaIeLk9743Zyb" - "f5LOSUH3AC3vyEWIuIw06KvHRmGqKIJ3+u1RzaD0BpL+S3DwfIO5oqAHDxPk1LOpr9oGe0/h" - "ArXHmSCjLbpIpSobyBa3o5DSWqJaF+xqlPykEE/LHFWmU2AkS1GZCdYkFajkjZhAxCghCLwS" - "zlCcE1j1BpOeE176gqU/mMBy3F0Rb/mpZENh0QWxyJNTfD6HRXfFthgNndFgcJzDa2aCv0WZ" - "tUj7blLdP9nZ6PCZATtPft+qjELt/vAm/HCzCNYmuA2O5xqzmzOwAuIG0AfGfgDFvqY+8bKe" - "lgAAAABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -aero_up = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo1MToxNCArMDEwMESarloAAAAHdElNRQfZAxkQMyBAd2MK" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAh9JREFUeNrFl0tv2kAU" - "hY+NBXbAElS0QTwColKX4Q+gbvmDXXXVriq160olq7b7Rk2zICsejWyUqkmQgEIMxvWxZAti" - "0eCoHo40ssZj+5vrO3fmXgmuut2u4zb0+33MZjPEJU3TUKvVUK/X2SRlOp067ZMTNBoNNJtN" - "JJPJ2OCWZcEwTXw/OwO50o/zc0fPZFCtVmOD3tdgMMB4MoHc7/VQKpWEgalyuQxy5Tv3VyiK" - "IhROHrmyUOo97QXuOM7+4L4CZ/uziVuSJG3CCRYFX5+AcDg5iURiP3Ba7bOE+3xde/H5huWi" - "4SHLV6uVEKAsy5uW86hbLBZC4FzpoVCzbVsI3OcFcP5yUfBQqBEuyufkhFb7Y+BMubheHguX" - "fXiURjH7sSw7yIKivh/Ao4g+KxQK6A1MvHr9wbuyv35a7arI8Gw2i+ubCd6++4KUlveu7PN+" - "rPBcLoer33d48/4bDvTDoLHP+xyPop0zR13XYfxaov3VhJZ5Fhr/+NlE62UFh090jMfj/wdP" - "p9O4uk3itDNB6iC/9bnTjoXjFxmUnu42AQ/+0GKZz+c4KuaQz6kPflBTJYxuRrtZnnJjlbsb" - "N/xtsc7x2+thkIH8S6M/9tbdkkbyGxwn1yuX3OBDsVj0Dpc4j1aCVVWFYRhYLpdQnrsV46d2" - "26siGK9xFoo0zhwO0bm4QKvVgudsd3F4JfLPy0vPv3GJVh9VKl6J7EaP9Be4+2JJRD7+lAAA" - "AABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -aero_up_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo1NTo1MyArMDEwMAycPlQAAAAHdElNRQfZAxkQOBMcU9vX" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAABFhJREFUeNq1V82LHEUU" - "/1VNz863yWyUyCSaEPzYuGtkwY8QYwLiQfTgwYsgBPMXeDJXvYmo+Qc8KEFIULyJHhQWNcSE" - "3KLrLgqLoMYVkplIdmZ2PrrL36uqnulOsu50YB68ed3V3fV771fvvZpSoDSbzS9/Xll9+czy" - "EFc3IkxLGlWNE/MBjj17RBljPlQE/uH1MytHzcEjeOGwwYGSQokvzigqbUCbo9UTAhhqKMqL" - "IW2PdpN2g/pbx+DH7xX02gWcPblwWi2dv2Debz2Dd48bVIxCjiiBFjBeE1iJwumkIg4If5ER" - "NRiKIxxgtOhpjVNfGby15xL0xz8NsP+owkzoPpqmiBP5MEL9RUBw9bWuwe6iwvRWOi2C0yhp" - "CO6kSzkVCWJvzBYqopBtScwdruM8sHj+wkYuiWGMBxTrHxrvQdZcMCat0S33qcgFbMBBTau0" - "y3CL6K0yfmxCibzDoYkz3pdelGbA0U53Ir4RqfHLmq9FcHVmSy1D+GbEphnNF5cdLFYuAR65" - "MsgJqNcwMZkFzxB5THXcbGzUXk1iGS240BGmPEw3lqwlkcyfcbNxGHbOKEW7W/M4cpVYb7Em" - "I+0pQM/qIHIq8w1NMnLyMwhdHw98pCOqI39/NwnnGY2tMKwwLjUL7tbE0Iqyp1Ot5/HqqOwJ" - "FyYot/MKA5EZMTOOfOi8smuv3Yc26RLdRWeMPLnOoU++oV/SVOTnmuzv5H22oFDLK1S4nRVZ" - "DTN0JK/d7pbLAB7vYn2i92jbHLg5AFp9KV6Fs5zreAy+ycg3+KDADiMDOZuuCibnMjYLeEy5" - "gPcIvsmQuwTvMKPbfWNrfTAIx5H36FWHDpR5V+A4g7c0x1RLIkYZwSWz+5yr57UbOgwJJgwT" - "tEuqt+lqhYNFLvSMUB2O69tkBB/adm1IuwBL9E47ZMA6lwIfOup71D6p7mv/98m3VvHC3AIu" - "tzuYI//2zG27WJy8cW1bBjyGFQ8+al5RQs02Ksvxyr4Ae9t/WqvV9t8k548l858JYeOlhsLy" - "yhrePHXaWrnPUg13DX5oNsDf/9zAO+99jnKtYa3cy/hUwRd3Bbj5xzre/uAb1Or7Rir3Mi7P" - "s8jEbz+yI4fm79fxyRdrqO588LbnH322hjdezePRvbP4pRVONOdE4PtrGr2rHXx7qWup3krk" - "+bGwjYceqNCB4bbzOnD9//yv86Tx/IEKGrvL205YLSssXds68iROcC+PRxXmf5WNfCsHpEF8" - "xwlLE/DUve7a6Z2kyO8reY0arwU3OPl4HktXctjzHCenw1V2l2oeKLF2Cjm3scQNZzjByUKO" - "WvfwoDdgSyyytxf4fZ5b5Az/qdxHnyoE3fW1wonFAMHiwmOr85cvzn26fBgHnzZ4uKyxk6BV" - "gvFgwc2GDsB1vEnEdjj+cA8BDyVo0+Eb1CbZ+5Unxr/OA3PRRTz5xILrnq1Wy1y+soxzqxHW" - "29M7ON1f0XhtTuOpQ/Oo1+vqPxxtdiUOpmR7AAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -aero_up_focus_single = aero_up_focus - -#---------------------------------------------------------------------- -aero_up_single = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAgCAYAAADqgqNBAAAALHRFWHRDcmVhdGlvbiBUaW1l" - "AG1lciAyNSBtYXIgMjAwOSAxNzo1MToxNCArMDEwMESarloAAAAHdElNRQfZAxkQMyBAd2MK" - "AAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGPC/xhBQAAAh9JREFUeNrFl0tv2kAU" - "hY+NBXbAElS0QTwColKX4Q+gbvmDXXXVriq160olq7b7Rk2zICsejWyUqkmQgEIMxvWxZAti" - "0eCoHo40ssZj+5vrO3fmXgmuut2u4zb0+33MZjPEJU3TUKvVUK/X2SRlOp067ZMTNBoNNJtN" - "JJPJ2OCWZcEwTXw/OwO50o/zc0fPZFCtVmOD3tdgMMB4MoHc7/VQKpWEgalyuQxy5Tv3VyiK" - "IhROHrmyUOo97QXuOM7+4L4CZ/uziVuSJG3CCRYFX5+AcDg5iURiP3Ba7bOE+3xde/H5huWi" - "4SHLV6uVEKAsy5uW86hbLBZC4FzpoVCzbVsI3OcFcP5yUfBQqBEuyufkhFb7Y+BMubheHguX" - "fXiURjH7sSw7yIKivh/Ao4g+KxQK6A1MvHr9wbuyv35a7arI8Gw2i+ubCd6++4KUlveu7PN+" - "rPBcLoer33d48/4bDvTDoLHP+xyPop0zR13XYfxaov3VhJZ5Fhr/+NlE62UFh090jMfj/wdP" - "p9O4uk3itDNB6iC/9bnTjoXjFxmUnu42AQ/+0GKZz+c4KuaQz6kPflBTJYxuRrtZnnJjlbsb" - "N/xtsc7x2+thkIH8S6M/9tbdkkbyGxwn1yuX3OBDsVj0Dpc4j1aCVVWFYRhYLpdQnrsV46d2" - "26siGK9xFoo0zhwO0bm4QKvVgudsd3F4JfLPy0vPv3GJVh9VKl6J7EaP9Be4+2JJRD7+lAAA" - "AABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -aero_denied = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAADxklEQVQ4jbWUzWuUVxTGn3Pe" - "+955k8nMJE5m0vqRZCaUYomG0uJGjDR0UXBRUj+6Kqg7kSy6SBf5A7ropiB07aK4qIsWIYsu" - "ioXBQoRKqWhJ1eq0sWqSmWQyk8y8H/e+p4t8oJ2YuPHA2dzD+fHwnHMuiQheR/BroQJQOxWv" - "Z7N9cRB8nAA+dIEBAIiAvwPgJ04kro1Vq/Mv66XtrCgVi9osLEx1K/V57+HD6a5Dh8B9fSDH" - "ga1WsXr7Niq3btVrUfS1yue/HH34MNwV/HM+n1HN5vd7+/vHsmfPQu3bt60i8+wZli5fxr/l" - "8nXT2fnJBwsLK8/XX/B4ZnhYqWbzyv5icaz34kXwnj2IrYUoBXge4HkQpRBbC85kkL1wAfuH" - "hsZUs3llZnhYvRQclMvnsqnUidTp04DWoEwGnE6DEwmQ44AcB5xIgNNpUCYDaI3UqVPIplIn" - "gnL53LbgmULB9YCp9LFjcHM5KM8D+z6o0QD+l9RogH0fyvPg5nLIHD8OD5iaKRTcTd6W/KhS" - "OZJOJgc7R0ag4ngd8gqhAHSOjMArlQbrlcoRAL+8oJhFjiaLRWhmrN29ixYzfNdF6LqIXBdG" - "a1itEWsNaA24LoQZ5s4duAC6hobAIkfbFDOQ78jlQPU6zNIS3jh/Hqz1jmolDFE7eRIqk4GX" - "zYKBfDtYJGDfB9VqkNXVV7IBAOT+fYjrrs9DJGgDE/Ns+OABkExCBQHmL10CM4OMAVkLAkAb" - "3hEAIgJZC7YW9OgRwnodzDy7xds8kF97et70iMrFfF6T1gAzEEWAMburBvBwcTH0RQbfX15+" - "Cjw3vIOl0tMgiq7VVlbA9Tq4VgOvrYGDYNes1esIoujawVLpaZtiAPitu/sta8yt/o6OVI/a" - "8X/aimVj8E+r1XCUeu/dWu3+tmAA+D2dHvetvdqtlDrgOEgQbQsMRDBnLWrGGM9xzozU6z88" - "X28D29VV/LF370d+HH/bFOntIkKGCJuLFwJYEcGqCDqJKh7zZ+88efKj09WFHcFbtuTzOW61" - "vghEPo1EDtiNdweASzSnib6Tjo6vum/eXCwUCm39dO/ePUxMTDizs7Oq0WjoMAy1tVbHceyK" - "iJsFOs4wv32AqF8AzMXx3FWRP5cAn4hCZo6YOdRah8lkMhwYGDCTk5NGzc/PY21tDcYYiuOY" - "RIQ30gGgKiL4xpi/AJSxvsIWAIjIAaBEJBYRx1rLxhhqtVqoVqu0rRXT09N048YNPH78mKrV" - "KjWbTfi+TwDgeZ4kEgn09vZKX1+fjI6OYnx8vA3yHxWIwp50Lj49AAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -auinotebook_preview = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0" - "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJXSURBVHjahFJRSBNxGP/d/+52" - "W66ildPKJB9EMSwjFSNoUkS+GYg9pi9R9tJeopcgC3yKYvRUMHA+VBJUmpQPQSySKINqEGSB" - "Np3aNjs3N8+7285d/7sxa9yw3/G777v/932/+76PP6PrOgw8D876dYImWJAEZPpW8l89nYea" - "i8KGgMHRYPitvgkCw0G9qaNXD4x80Qs1BknRnzaBEfX1e+G758PQaEgvnP8VULA5lCS8/T7T" - "NUQK4ApO4j/1l3s6N/zA8MiGTxiGgUGowGwkhqkfc5Bl1SKwlM6i90y75dzsoKX9fNPLF2Mt" - "sZVGuMt3YPDpK7jsDnj7uiEIfH6ClAjF5rAKHD1xcW99a927C5e6hP3luwCGwONpRjwm4tqA" - "H7du9pmJDG9HrsSeSE3dvmdnz512tFZVQaGjaCyBjedRubscxzva8PrNJzNR0xmsKsQq4KzY" - "fqDW7UY8o4KjxRzLmpYlBLUNNZj48BVRMQlWA7I5yTqCvcyuq+s0qmkQiC1/QeiTo1ajNpWS" - "oMoMVJVyXbZ2sDj9S5sMh2l7CjJUJGswq0HNZBCNLmEhPA0xsQpJUSHJJUZILCbuxuZF7fv8" - "ApbTaaysrSEpSVgURdy//RDJxAp2RvzgMgkQzbpEziVEbgQfBeuXPY1dqcMS4W08cnIWY0Pj" - "iIXjuNI2A0dsDmXyT3yUTtESZ5EAU3CuDvhD7ydDB1mWg6zQWelSj2ydwbE9v1Fd4TQZmHLj" - "yTfBzP88PsgUCZTCne4qFycID7Zt4TuqK50TFaTmZMP1x5l/c/4IMABbKBvEcRELXgAAAABJ" - "RU5ErkJggg==") - -#---------------------------------------------------------------------- -whidbey_down = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACsAAAAeCAMAAACCNBfsAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAaHWVZ3egZ3e1cYCncYa0dpC4cYXGcpDBc5fWd6Dld6Pwi5OzgJbUkJjQkqHC" - "hafggqfwh7Dwk6Xgl7fwoKjWp7fXsbbWoLfnoLjwpMLwscHnsMfxtdD0wMHg5eTo5/D49/f3" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAverH2wAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAF4SURBVDhPbZTpYoIwEITRGqAQ1ChqOFrx/R8y3SObq8yvsHwZhglaOdH7HZbJIp1W" - "YW7t7w68LOcwDaxd5+lhC3q18zwOMhTWIjtZ+3wGfFmWFYZjgJl9vWC/1x30AI2zzExzIcqz" - "a2RxC2Ak2n4zJmEx1TgaY8R7AtHsdgMS1IivJRZHyN5lA6PMEgwZ2JVYs23bxwuWG3PGdF3X" - "ImvtBO/KqAl38ytgO+WqMz1SDDz7KXaCbatU5YYARt+SbUHg61zT9/iMHsQZKHBI9A1S6njk" - "fpuCRTjmJVQBymfxlfuCc5IX0cMhnhvCMYO8KCdCV0L9GbMz8Fhqous1ugbWw/32k2oDtFUn" - "do2sz1ywqWvCElz6pq4pS3CRVxooMvjqsI2+v5LwXCVrljfrGclhqH2v5e+Nr6VnYltgBct7" - "iDDExm+grvm0ouL/QwrjN1CHXvczYAz0xF5Pp9w168zfAhjeH9gSle8hnWutldL6H7rHOq2P" - "agd1f/M7VhKuYPh3AAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -whidbey_down_single = whidbey_down - -#---------------------------------------------------------------------- -whidbey_down_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACsAAAAeCAMAAACCNBfsAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR" - "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagcHiYZ3egcHilUHjRQXLwR4DwU4Pw" - "YIfTcYXGcIjVc5fWZpHxcJj3d6PwgJbUkJjAkJjQkqHChafggqfwh7Dgh7Dwl7fwoKjAqLDI" - "sLDIl8D4pMLw4Of35/D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAQS37pgAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAGeSURBVDhPfdOLUsIwEAVQCCixFSggVfBFQWpVjKJo+f8fi3ezSZq2jDsDhHB62Wyh" - "o319Vctg9V2tO34p5H0bHw5D4Xe9FULK5bKhb6UcDs/cprNdMYiprhee30khaStx2NpudwCb" - "JHG8WAhbEkU0cZgtUge0iYrjCEUuilheOWysS2U9GpluGJJ1mKyg1LHZn6NYNNYUCWuozSjr" - "FVxnLGQUjZPJlLJKCk7piar0Nk2zS90RAhINVDZN5yUeNZuhbjq6BzmZomYoICr/Yr5mtcry" - "fL2mfnvjSd2anvkSsqBZUazN2XS/YVNLrc2Qut3yHAj/10OWFwVRtrpPvZo5cL+28A7fnxfv" - "G6Ps74GwsfXCsXKkMnWWko39DKukAbjUygKfskFqYLnnKvcHdQT9sA0EPdgD1ts9Vr2G/fpp" - "pDMeAg3gWe2fgn9V9d+0yW5edCylQurnwJejZ/7VPJpZ7V+C1PBsFrPFXAul6rSRi2S2uFmq" - "kdrK1frcWOq1kXrC6osHulnq963Wa3Nm9kOySrVpq1/yr5vNbtdK1foPGIxy6qmqIg0AAAAA" - "SUVORK5CYII=") - -#---------------------------------------------------------------------- -whidbey_down_focus_single = whidbey_down_focus - -#---------------------------------------------------------------------- -whidbey_dock_pane = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAaHWVcHiYZ3egZ3e1cHilcYCncYa0dpC4ZobHcYXGcpDBc5fWcZjgd6Dld6Pw" - "i5Ozl6e3q62xgIjQgpXEgJbUkJjAkJjQgJjggKDXkqHCk6TWhafggqfwh7Dwk6Xgk7Tkl7fw" - "oKjAoKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo" - "4Of35/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAA1jVbdgAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAdFSURBVGhDtZpxe6I4EMbtbQVXrHJuaY8KWq/XW3Sr196u8v0/GTfzThICRIh9nssf" - "u4rw42UyM5kJHVVXjDQah/EV51ejK05+SKMwjK/BX0Gfzu9ms2kY3PgL8qd/nc/vCB+GN/54" - "b/p0sVjMaRA+9Mb70hku9GvUe9IBV3TC+9rejy5wTfdX70VneJ7LHRaLu7uIPNPL9j50hp+a" - "w9NzPOhQfvrHHqeZn/phOmzeofvZfpA+zTFa2rNsFk2GPWeIruB5y+5En00mg1E7QNfw/CSP" - "oEaZ51kWDavvpxu4phOWB+hJMqi+l17DFb0sBa+eJB3KOX30xLIFeAQXvKYTvtf2PfTVbrtd" - "6xsonrKMoafhJAwu5/vL9NWO6Rp/iZ5OJsFlfI/2onh7oxvQYKOsaeALjTV944fK2DFn489o" - "ryqmA69NDrtjWPSwZyHs9RlWr+h5Qzt9UdqzPvhATTBMn/Uu4QOxut9r24vFdzSUvUh+lk37" - "6wMXfVNf8sF0mdrt9nGF8YbB3ppNl/WpK8eNHPTNxuCXHx/a9q+vZz3exZvW6+m5NPhi58B3" - "6Yfj2zYRHcuSgOI5Bi0fDgeiT/nT8oxTi2K3U1dZz9ChH5gu+GXJ9HNRvP/dgoOfyEGox/Tn" - "nVlo04kNm34DHPRfv7psxuujywqm4rBo41t0Vs4uvl4/PXHUNLj7/f6VRvte5RJTjxBo4Zv0" - "A3sDxw2d+EeTcnzd4qnIdR43zZ/EbSUjNfEN+oHppFsiEZOmxn5/ZJOBvt1uNivrNyvk2nib" - "fmA6W0W0Z6FGkL0sNvLYt0L/aKeLtnqLTvCD2FzRNR53VelSZ8l1IfhfdqqDbRaWcWo6nWZs" - "zrk1SZLVvww40oBeZTG9oDwbOm6pDy8svKHzA9Y2Z3oUgU5WOSIXdOjAv/Nv1hLJ5aZRr+lQ" - "XhNYevSEZye6ZJo2PZNpd9ANXtFFuYtOM0p50UnP4Dm2VeQZavVCZ6cqudziCOL/szSKYkh7" - "hReu62UJv/MyS8+HM2AZuUwNgwcdTlVSkasrrppOgSL0Rg2ME9l6uD8/cqmWd643T0Y90xEO" - "azku48RzCu0vau1z0lNEhJu++Epkoks4dOhjPPaL+Hl+gf4upmlplzaIPGdUIbewXls7OTvo" - "xktbdK6auNyAWz266fOHaoQ4ZKNpOl940vRXHQN99BU9XMkzqylo3+7u0nTEdkHkKzoKRUNH" - "tccxeoEOwxs6XQqK0GdRNFoVKkqEDo+8lk4Syq2UsDWd2ubxKHtm5dzVid1Fe5bOjCx4kUt7" - "mohf8QPCMg3ttGERjp4z1Yk27O5HV15r6MbuVF1S2xbHo+pRNblNf88SaN9sVIpyaSfDYhnU" - "dEQK7A54ELO/f6VJqC2joknF4bmfPgadw4UtY+hmo4Vj9ZanWNtd07PsRfmDuYqTgc43nAei" - "e8TEu4OuWh7kGcb70kViKfR7phdvVA808gw34thHkBzJ+EZHSquH5NfzN5p1ZU+S/kM3fZxE" - "owBnCF2lWFAivcWi8jvUYydDBujAZ0JX7XD5Q0yTMT0EnVf6emHh9FC3anptgu3nc5ueppC2" - "0nfT//OdqRcOA5HeoVsbFGZdFbxFJ3/7C3ShyTPoz/C4PwHnhau+rLmxVdcEwNunRdEYNcFK" - "8Wv6jO4cBL8DfuC1xbqssbVi1TOMN6chHoSu1Ws6ByLZBfDzObEX8yRqNvd2LaZsLzt3k8lY" - "1g8aDw+Ukc3gfatAzMJjapTnOdEb2yqNOtLgSdwkMHBWGEIxxmQS/iYTqvAyGSmN9rZEswZW" - "eJkaC0Af4/ieBrPHY6kWWniCh+0NoVb9DjzbPLhZNhH07f4+CIK4heYbT0V7d0ui3XvcSvLk" - "QEbXROPnz859zFGOLGptZhRDru2UTt9EeB3ISj31TQ784fBIRwVeVTQtrq2gbs93G0Vfvtg9" - "3/Ft92KqdXWfI1cpVCspOOMnjg3QLr0aRwpOxuGOj+i7orD6JarnqVugEE2sfnXs2khx0CsD" - "r6rv33U3w/3MZvNCQ/dP3EI+1c2pa5fGRbfa2e/SApohXbw6RmFk0a2rzMd+ujRclAI0XnYh" - "pBRH1ujfhuil6yZX6LTEmlEnl158H91uFVVtr+t7ne0o9iKXSdSxHjpvLJieqLmXar5xaPfs" - "Ll2mP8IMWqRzTy/PSTplzIvqe7Qndit3gc4581Paq4p23lHpYP+dH6K5lyoZSce1U3+vz0xb" - "dMZLgcD/AB5aode9Qb+/S5VmtEsDUNMH334MxKqpcxw+4/HWbIAuNSbXgc3RLIo+4zNyjeBR" - "ZdbjRKuFKec+F03qqrpCtuieb/uGLGNXyDbdR7mugXsezlUhn06D3iJED+2qvkcDpCpUvzdl" - "nnTVnSg6vavxfT/spb1Wz9qpnPN7Q+mrXTsmF1I+78j0PHpq13jOLR7v966mV6jS0BX0vAJq" - "OZ+3dlLP8UnDH+7nkUpRHMf/399CVFUcf7nu7zj+A8yummsi9EdGAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -whidbey_dock_pane_bottom = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR" - "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagaHWVcHiYZ3egZ3e1cHilUHjRQXLw" - "cYCncYa0dpC4R4DwU4PwZobHYIfTcYXGcIjVcpDBc5fWZpHxcZjgcJj3d6Dld6Pwi5Ozl6e3" - "q62xgIjQgpXEgJbUkJjAkJjQgJjggKDXkqHCk6TWhafggqfwh7Dgh7Dwk6Xgk7Tkl7fwoKjA" - "oKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo4Of3" - "5/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAaHenigAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAejSURBVGhDpZkLe9o2FIYpTVeWrG3Srmy9stk0LTPJMKMhmYM9KOuSERqydAX8//+H" - "dy6SLF+QRXeepwtg+9XnT+fotlqyRQRey+1vcX9S2+Lm08Bz3f42+C3ond5xt9txnRf2guzp" - "b3u9Y8C77gt7vDW94/t+DwLwrjXelo5wpm+j3pJOcEEHvK33dnSGS7q9eis6wqOIW/D942MP" - "MtPKexs6wlfZsMwcCzopX/2jx6prp76aTp4X6HbeV9I7EUVOexh2vXZ15lTRBTzK+Q70brtd" - "WbUVdAmPVvwKIuIoCkOvWr2ZruCSDlgMog+HleqN9BQu6HHMePEmQdWYY6IPNS+IB3DGSzrg" - "jd4b6KOr6XQsGxA84YyiB27bdTaP95vpoyukS/wmetBuO5vxBu2z2fU1NACBpowh6AvEGL7h" - "S4WYmN3W12hPEqQTXlpOvlNodNcwERpzBtULepTRDl+E9tAEr1gTVNO7xim8olbnc+k9O34F" - "IfwC+WHYMa8PyuiT9JHPSOeunU7PRhTXFJitYWeQ3joqaaiEPpko/ODzZ+n9xcVaxi1n03jc" - "WccKP7sqwRfpi5vr6ZB1DGIAcuYoNH9YLIDewU+DNd06m11diae0dyjQF0hn/CBG+no2u73M" - "wYk/5B9JPXV/VOiFPB3Y5Ol7ghN9uSyyES9/HSRkFZZFHp+jo3JM8fH4/ByrJsOdz+cXEPm2" - "4gF1PZVADp+lLzAbsG7gxt+zlJuLKb0VpM7ZJHuJ05ZHpCw+Q18gHXRzJVKniZjPb9Ayok+n" - "k8lIu6aVXB6v0xdIR1dYe+hKBPilsWkcez+TF/XhIq9eowN8wZ4LusRTq2K4lKPkeMb4pT7U" - "kTe+Zk5Kh9uU5zi2DofD0b8IuIEgvcIxOaF8UHRqUv7sa3hFxxdMPUe65xEdXLmhsaBAJ/wt" - "XtOmSFxuKvWSTspTAkr3zundgc4jTZ4ecreX0BVe0Fl5GR16FMbFUnpImaO7wu+Qqmc6JlWM" - "yy2sIPwbBp7XJ2kXlIXjdFqi6zjNwvvRHeQMPyZC4YlOSRXDIleuuFI6FArTM2tguhHdo/bx" - "lWMxveN6c6XUI53KYcy/c6ywT0n7RzH3ldIDqohyuv8WyEDncijQW/TaHznPow30W7Ymp523" - "QZA5tYTGFtSra4dkJ7rK0hwdV0243KC0Oiun906TGtUhmibp+OBK0i9kDZjoI3i5GHtWUmj7" - "dnwcBDX0hSpf0GmhqOi02sMa3UAn4xUdHiUK07ueVxvNRJUwnTJyWzpIiKe8hE3psG1u1cIP" - "qBx3dew7aw+DrpJFWVSmPRhyXuELkjMZ7XBg4dY+hGInmvHdji6yVtGV77C6hG1bv19LzsQm" - "N5vv4ZC0TyZiiCrTDsbSNCjpVCnkO8GdPub7W+iE1BlRTaIO12Z6i+hYLuiMoquDFqzV19jF" - "0ndJD8OPIh/UUzgYyPEGxwHvhGritoQutjw0ziDels4SY6afIH12DeuBzDiDG3E6R+AxEvGZ" - "HSnMHjy+rt9Drws/QfonuenDQdRz6A6miyGWKJ48YhHjO6mnkwwOohM+ZLrYDsef2JoQ6S7R" - "caZPJxYcHtKtmpybyPteT6cHAUkbydbkX2wZ9sKuw9ILdO2AQs2rjNfokG9/EZ1p/A7yM2Xc" - "nwTHiSt9LHuwla4JCK/f5nktWhOMBD+ld6Flx/mN4AucW7THMkcr2noG8eo2qgemS/WSjoUI" - "vhB8vR7qk/nQy27u9bWY8J5P7trtFs8fEKenMCKrwHMrh23B6CjlUQT0zLFKZh2p8CCu7Sg4" - "KnRJMUW77b7kDhV47owAIn8skV0DCzx3jQaAj/3+CQSyWy1eLeTwAHfzB0K59Tvh0XPnxSCL" - "gG8nJ47j9HNobLjD2otHEvm9x2sePLGQadcE8UVZrLf3hdIVKwu2Nl2oobLjlMK+CfCykIX6" - "ekPvAdHC5eWDOtNp3wTdUnYUVNzzvfa8V6+0PV+93mg8f56z6WWj8eDBPaSLLaXbbZccgBbp" - "ScsTcDBnvb5Tv7+H8cMz1cCrRr2BP+3f0/arrbKDlBJ6ouBJ8vedO/eBvr+/t/fsWV1EAwLh" - "+/v3ztPNadkpTRld286C8vuIgdjb24VA8u4us78HvHZvyUczXSpn/sOH5BGjkV6JN9LrqPwR" - "kZ5CMDP32XjKYaITXOhcZkNryTOYY6ADe3f30f7BY9S7RPFN/A/GUtGbzcPvNuM30+t1YIMt" - "Kb3ZfLqEfxn6IcSPG/EG7XeBffAY4gkEYDHUH3qVN28Oj47evfsa7Uly99FBlk7ecyNIB/ih" - "7xvg5lO3nRy9KeCCfgjKu8ZjN3O+7xidOTzy/f91preDnlPOsO8i4Bu4cuR/zZme3kuIJ3o2" - "oEOPQHnFgWH1/wEFPNFx6lexxGSpVC7XkaaxaKeUbqPchp6Q96n2TxArgP9RZYtaA5vHUcRn" - "bV9ZeJ6usM10Vt98wgmDyfJrNP2l4hm6XDF7CATiZTZih0aRFdySjup5/PqZMlEe5Vbpt9Oe" - "AJ7pkOewhSie+Ja3Y0tPdpgOBRrZKrf1HZV9Q3T03Fb5NvTk25+wQKPrsyq30+vWzsAjSI+i" - "LeC2OcNyTjudc219VP0O/wGW4JFYg7jH7QAAAABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -whidbey_dock_pane_center = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAGDeAJUqQIEOkIkewJFKlJlayMlSiMle1K2G0LmnSNnDgR2OkQ2O1UGagUHCo" - "VXSzaHWVZ3egZ3e1cHilQ2TAQHDAQnLSVnfFQXfgcYCncYa0dpC4VYTTRIDjVYbgZobHYIfT" - "ZpPXcYXGcpDBc5fWYIjgYZHgcZjgd6Dld6Pwi5Ozq62xgIjQgJbUkJjAkJjQgJjggKDXkqHC" - "k6TWlrDXhafggqfwh7Dwk6Xgk7Tkl7fwoKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjpMLwscHn" - "sMfxtdD0wMHg6tTN4Njk5eTo4Of35/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAXehG6QAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAdqSURBVGhDtZoNW9pIEMc5emrB651VUDRUpEkqb5d6SBOUXq9Q8dprke//aXLzsrvZ" - "hGWz+NzN87RCzP74M5mZzGyspDvYOGh4wx3OTys7nPx+HHjecBf8DnS/3wtD37t47S7InX7V" - "7/cA73mv3fHOdH8wGPTBAO85413pCGf6Luod6QQXdMC7+t6NznBJd1fvREd4kvAnDAa9XgCR" - "6eR7FzrCV3lzjBwHOilf/a3bKnRTX04nn2/Q3XxfSvcTsoL2OA6DdnnklNEFPCn4Hehhu12a" - "tSV0CU9W/BWErZMkjoNy9Xa6gks6YNGIHkWl6q30DC7o6zXjxTcZl9UcGz3SfEE8gDNe0gFv" - "9b2FPlnMZlP5AYInPKPoY6/tXWyv99vpkwXSJX4bfdxuX2zHW7TP5w8P8AFg6JQpGL0Bm8I7" - "/FIxBmbYeI72NEU64aXLye9kGt2z3AitMYPqBT3JaYc3Qntsg5f0BOX00HoLL8nVL1+k79nj" - "CzDhL5Afx769PzDR77Il35DOl3Y2u5mQPZBhtMb+KDt1YvggA/3uTuFH375J33/69CTtK0fT" - "dOo/rRV+vjDgN+nLx4dZxDpGawBy5Cg0v1guge7jq9ETnTqfLxZilfYdNuhLpDN+tEb603z+" - "9a8CnPgRHyT1dPmTjatQpAObfPo7wYn+48cmG/Hy6CglV2FaFPEFOirHEJ9Ob28xazRuFIYt" - "sjjOf9p6RJeeUqCAz9OXGA2YN3DiHzrjw4du66zT6VyCNZvNdzk+hy1XpDw+R18iHXRzJtJF" - "Y4uvrrpdgBP98vJds9vNfqmlXBGv05dIR6+w9tiThLet62tkn50h+xzs8GVL/lIvF0X1Gh3g" - "S/a5oEt8+PYtws/AFP2wxfgfeqkj3ww052R0OE35HGtrFEWTfxBwDUZ6NauDnSq6LNNM1/CK" - "jl8w8znSg4DoEcDZG0U64b9indBukdhuKvWSTsqVV+iOH9zSBe0C3Eiv/3yFJxjoCi/orNxE" - "73YBbqbXiS5vAJn+TD3TMajW2G5hBuHPeBwEQ1wbtjrklfuCoePrtVDgsV3QujWFJzoF1Rqa" - "XNlxafSOoOO1zeye6TWkf8KvvBa3d+w3V8r3SKd0mPJxthVeU9Q+adno9Rco3kwfXAEZ6JwO" - "G/QG6nKhg+cL2nkMgsippFRbUK+uHYKd6G/edDoUiPcmz9TrB3jSjZnef59WqLag0yQd262V" - "pLfedC5L6RMImzXEPK1EjTS+9XrjcQX9Qpkv6NQoKnqzc8lZZNOu6LBUo4dBUJnMRV1hOkXk" - "rnRIqPWMW9iMDmNzoxLfo3Kc6tjvrD0eh1Qhm5BI27XX9qt06YnOSzW673mV+1hMojm/P4+u" - "/A7dJYxtw2ElvRFDbj7e44i0d09F9TL5vba/f6Rrp0yhq0rwiyHG+xVc4swzIpugijnQq0TH" - "dEHPKLraaMFcPcEAkn6X9Dj+CAs/NM/PMedVzMhyg3Vg/6A6xhpsoIuRh+oM4rfSD/P0Q3qP" - "dQbolEzzB+gHcnUGB3HaR+AaifjcRAp3j3iCS3svqV5J7Z37jL63R9IFXZRYogRyi0XUd1JP" - "OxlsRCc8weuQTmwd/gGH9gUd7/SyjcCF+vaQvDeR7/t9nT4mZZNXzC8asKsBnrBB1zYo1H2V" - "8RodEvnPrfRaDei/ERwb8GxZfmMr6wkIr58WBA3qCU5Pi7qJXf2V4Eu8X2rLclsrWj+DeHUa" - "5QPTnwr0GhjQCQ4tQ+bzJImC/HCv92LC97xz1243qMKjvXpVq0n9NchQpRx/6SvlRM9tq+T6" - "SIUPcfdFwZ8mk9oLVMxksJ+OKEnZfAywOB6DFbcl8j2wwPOlydbDq/DgYG8P/6Funa3wAPeK" - "G0KF/p3w6POL16McHfQfHR1Uq9W9XwIKRM2GpB7gG1sSxdnjhIsnJjJNTWDfvxdo2lG8Y8Bo" - "E0IOmbZTNuYmwMtEFuphbjLgl8sbOMrwNPXMG1mbM99JEBwf6zPf48Pi47zAf8QuJUK6GCm9" - "sG3YAN2kp41AwME5OPEBfTGfa/Mq9PmPcBAmQ21ebZg2Ugz0VMHT9PNn3odAgyn57iPYjBta" - "bKz922w4Ne3SmOjaOPuZR0BlPMWLY5BGGl1bpV7a6TxwQXmQeN6F4FacqoZ9G8JKl0Mu0++0" - "75AVFyveRtdHRdHby/5eVjvIvcDkEnHMQseNBTUT5fdS1TtMbcvu0nb6TW6SM+7pJQlIh4K+" - "Vb1Fe6SPclvoAdiztKcp7LxTp0P77+jp/F4qVySZ10b91pjxC3TEczeF/xHc01Jv8wPs8c5d" - "mtLOA0BGL336UZKrqs8xxIzDU7MSOveY2AfmLd8UPSdmeA3jqcvMbAV3C9XOPS+bxKqsQ9bo" - "jk/7yjyjd8g63UW57IEtX87UIa9WpdHCRAftor+nAYhbl//0OZ+cTgQdntW4Ph920p6pR+XQ" - "zrk9oXT0jApMbKRcnpHJ6+ioXcY91haH53s701Pq0mgOtTwCKgSfs3ZQj/kJ5g53i0ihaDgc" - "/n9/C5Gmw+Hxbn/H8S+cD8xcYY4GnAAAAABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -whidbey_dock_pane_left = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR" - "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagaHWVcHiYZ3egZ3e1cHilUHjRQXLw" - "cYCncYa0dpC4R4DwU4PwZobHYIfTcYXGcIjVcpDBc5fWZpHxcZjgcJj3d6Dld6Pwi5Ozl6e3" - "q62xgIjQgpXEgJbUkJjAkJjQgKDXkqHCk6TWhafggqfwh7Dgh7Dwk6Xgk7Tkl7fwoKjAoKjW" - "qLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo4Of35/D4" - "8Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAA+wCLtAAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAeDSURBVGhDtZr/f9JGGMdprZPJnHSKm9OKI4DG0K5kWAptGIw5FGqpdQL5//+Q7Ply" - "d7kkR3L4ms8PWmjyzifP3T33PM+1FO1gQ6/u+DtcH5V2uPh86DmOvwt+B7p7etLpuE7jmb0g" - "e/qr09MTwDvOM3u8Nd3tdrunYIB3rPG2dIQzfRf1lnSCCzrgbX1vR2e4pNurt6IjfDTiJ3S7" - "JycezEwr39vQEb5OmuXMsaCT8vUn3dYdO/XFdPJ5hm7n+0K6OyJLaQ+CjtcsnjlFdAEfpfwO" - "9E6zWbhqC+gSPlrzKwgLR6Mg8IrV59MVXNIBi0b0fr9QfS49hgt6GDJevMmwKObk0fuaL4gH" - "cMZLOuBzfZ9Dv1xMp2P5AMETnlH0odN0Gtvj/Xb65QLpEr+NPmw2G9vxOdrn8+treAAYOmUM" - "Rh/AxvAJXyrAidmpf432KEI64aXLye9kGt3J2Qhz5wyqF/RRQjt8ENqDPHhBTlBM7+Ru4QVr" - "9epK+p49vgAT/gL5QeDm5wcm+n58y2ek89BOp4NLsmsynK2B24svvTQ8yEC/s6/wvc+fpe9n" - "s420W55N47G7CRV+vjDgs/Q7D+/fE/heCECeOQrNPyyXQHfxp96GNM/ni0U/oz5DP3iIdML3" - "QqRv5vPb9yk48fv8Jamn4R9lRiFNPzg8rCJ+j+BEX62ybMTLb3sRuQqXRRqfogP88BDo9/b2" - "LnDVJLhXV1czsPSzwh4NPS2BFD5JP3j0E1j1YeUeqE9SbmZTmikwdQaT5K942nJESuIT9INH" - "TK9WAL+n46+ubm54HqJNJpcaX1tyabxOBzjR0fWofl8ilkudTXHs7Vz+Ug8XafUaHeFEl+ol" - "frlcgmy5pjhKjueMX+mhjnzT1ZwT0w8eVcHwCfg/eqdc/hsBN2BMVNGeMH8pOj1Q7jNdDa/o" - "oDxDr/+LMw/gpDtDJ/wt/k7bIjHdVOolHd2SpFcrv9K7A50jTZoe0FrdGOgKL+jkcyMdRhTi" - "opEe0MzRvcLvEKtnOsJXutXQ7yRtRrNwHG9LIaVltO9xLCDPhPw1m8ITnZSv4M1XT9BqtRXS" - "f8ZbYaEwPZEDfxJ0ws/QaaHY3jHfXCv1SP+OmCl65elTvPWd2PuM9KGznd59BWSgf0/wtPYK" - "wYHO+/YW+i27JqWdyyCYOaXo5csamK79SW1V/fE+rVRc/DRXUnTMmjDduMCLBmb66XlUOm+3" - "k3T0vaLPbOiX8HIhjizmgOh3Kt9OTobDknt8nKCvVjiq1Qprp2wvRzs5XtEBr9E7npem07Tc" - "lQ4SwimnsDEdyuZ66WLUPW63flN+B+3o90qZtctlbvL7sO/58gXJMwnt0LBwgD46Pm614lHd" - "ge6l6MrvkF1C2eb7pWhwDeqBv/qorSapfTIRIcqkHRxL2yAODmqnzJ5GleANH+f7ACLDcbtt" - "pG/y6XWi44JL0FWjBddqf4r4BL1WuV8+Eo5XmjAYyHiDUcY7q+Mltwa6KHkozvTRNxl62Uhn" - "B4RMP8NL5teQDyTiDBbi1EfgGAnqf1+vtSBZk47fvA107R9l0RcMPc9rULBgOsVIESk92WIR" - "8R0KMJ45HCNrSC8/x3sDpotyOPzIrgmQ7hAd9lxtY8HwEJdqcm96MwXntFtM5m21Un5PvkE2" - "1DD0FPyfDdgsPUPXGhRqX33TpXmp6LhrM13ydDrNONrTl7hxyX01qVz6HX3v/onqdfqDB/8Q" - "XvBjegdmeqPxB8GXuLdo9ERrRctnoFWi06uVB/uYEyj1ko4LEfxC8M2mr2/mfS9Z3Ou5mBvg" - "qmo9Qbc/flyt3uX7N5vz875m2LdqsFvQXKV8NAJ6oq2SyCNJfatFdA2OCh1STNZsOs95QAWe" - "B2YIlm5LJHNgUk/0JBwwvn8Ghux6nSJjGg9wJ90QSuXvLvqG4b0kAj6dnTUaDT+Fxge7rD3b" - "kkjXHp0O8GHW38Xag/lfvmSeo77FlQWlTQfWkKmdkqmbmE5RQqiHusmAXy4H8C3DowiGxdQK" - "ytZ8r1+320dcvXHNd3O9eKeydfGcGywJIFcScMQ3DQ1QQ736uv2DLA1B/Rzpi/lcq5cgn4dq" - "AZZoX6tX66ZGioEe/RLXnR8+yGoG65nJ5B2YrJ+whLyILzV1aUz0+I7oA1RLXCuxcRUvvoNl" - "pNG1u9SP+XQuuCAESDp3ITiZp+CS34bIpcsil+mwxSqLg0suPo+ul4q08bCJ9J2kQ0bnmVwi" - "vsuhY2NBJkupXqrqrGLCmNNd2k4fkBtk5Db29FA7Rsyt6nO0w1Ye2xY6xsyv0g67FZ90cP+d" - "8oxEL5XTuSOxro36c+eMm6IjnhME/IfgTh68oKf3IqmdC4CYXnj6UbBWER97Rg0Day/qYOs5" - "gXngST08wXB2UKi8mB4xvps+96C0oPDMqcAz8ELs+/SJ0P90ZsP4DN1GuYVnhPpvdlYm1FMB" - "LTJUu5MyO+3S94IOZzW258PFo0ozVc571A7pnN0Jpa12oR5Phq3OyOTasdQu8RhbLM73dqZH" - "L1A3VQU5R0CpBW+tHdTj+gSzh+/0txC+73+7v4WIIt8/2u3vOP4D32mBB1S/lsMAAAAASUVO" - "RK5CYII=") - -#---------------------------------------------------------------------- -whidbey_dock_pane_right = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR" - "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagaHWVcHiYZ3egZ3e1cHilUHjRQXLw" - "cYCncYa0dpC4R4DwU4PwZobHYIfTcYXGcIjVcpDBc5fWZpHxcZjgcJj3d6Dld6Pwi5Ozl6e3" - "q62xgIjQgpXEgJbUkJjAkJjQgJjggKDXkqHCk6TWhafggqfwh7Dgh7Dwk6Xgk7Tkl7fwoKjA" - "oKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo4Of3" - "5/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAaHenigAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAe+SURBVGhDtZr/W9pWFMYtW1en67RzunWdpUvQlgWdMCoyJFkotbaRCrMryP//f2Tn" - "yz25N19ILn2enV8Qkn7y5s2555570414jRh4dbezxvnxxhonXww81+2sg1+D3jw7bbWarvPM" - "XpA9/eXZ2SngXfeZPd6a3my322cQgHet8bZ0hDN9HfWWdIIrOuBtvbejM1zo9uqt6AgPAr5C" - "u3166kFmWnlvQ0f4Ih2WmWNBJ+WLf8xYtOzUV9PJ8xzdzvtKejOgyGj3/ZbXqM6cKrqCBxnf" - "gd5qNCpHbQVd4MGCb0HFMgh836tWX05P4EIHLAbRe71K9aV0DVf05ZLx6k4GVTWnjN4zvCAe" - "wBkvdMCXel9CH96Mx6FcQPGUMwl94DZcZ3W9X00f3iBd8Kvog0bDWY0v0R5Ft7dwAQg0JYSg" - "LxAhfMOb8jExW/Uv0R7HSCe8WE6+Uxh0t2QiLM0ZVK/oQUo7fFHa/TJ4RU9QTW+VTuEVY3Uy" - "Ee/Z8RsI5RfI9/1meX9QRB/pf/IJ6fxox+P+kOKWArPVb3b1qT8XXKiAPhol+O6nT+L99fW9" - "xB1nUxg275cJ/rvjV3l8nj6d3Y57fGJ3CUDOnATNf0ynQG/iX917OjU6Pn6Vx+foU6QzvrtE" - "+n0U3b3PwInf4x9JfbR/cHzSzj3iLB3Y5OlrghN9Ps+zES+/duO7h/tMz+IzdFSOKR6Gl5c4" - "alLcyWRyDZG91rL7cBfjGPiZHErTp5gNOG5grPyVpsyux3RXkDr9UfoQw3ePgJ5J0RR9inTQ" - "zSORHpqKyWSGlhF9PB6NhsYxgP9IdMSn1Zv0KdLRFdbuu4IAvww21bHXkRxEONEPjtCblHqD" - "DvApe67ogqerqnIpVTKMGD+vPd5mY3b3ITLqNR3yOvEca2uv1xv+i4AZBOlVjsmE8gYPvnv8" - "eFvhmX7S/ls/2oSO4097jnTPIzq4MqNakKMT/v2mST86Anz7dxm1QiflmoDSvUu6d6BzpcnS" - "fXrsSGfxqB28B/xY8IrOyovo8EShLhbSfcqcXzc3t5lMgeqDQJUSpmMdX2K7hSMIP/2B53VI" - "+jVlYainJTqO0yzcH51RQ/pcx2LxR6AqFdGpDi6hyZWOS9OhAjM91QPTiege0jc3t7b350r7" - "PAw/zsEcVo90moFC7EM1HZ4pab9Sc18hfUAj4jBHh7xk9UDnCp6j1+m2rzjPgxX0O7EmpR1H" - "VRD0kU61BfsrUzskO9GTLM3QsWvCdoPSCo1P0Skvg9t+vEHjEEe+0PEfLoR+LWOgmn5wMIeU" - "Ad9D+OTMudxAX2jkKzo1igmduj0coyvoZDxrBzJgFf03rGhAH0ZqlDCdMnJd+hbSKSWFjvl/" - "ctLc8N+gclzVse+s3R+0SNYQnyi1v+mMJN8HPc6rGtH3Te1Cf+OrlWjKdzu6ytra1ve75Ln2" - "nSra8cVG3FeL3HS++z3SPhqVaG95Hk2DRFeFQPmO9BcvMN9fwgpdO0M+LGQc3pfT60R/ipVA" - "j9VwvkcV51seq89x70J8F7rvXynj+Rflu9QbrAPeOY2Jpzk6wb9RlYDwtnSeO5ZMP0f6T1CA" - "M9r39va+ljrD6lMrUpg9uL7ev4anrrV/lEUfFlHPoTOwvJs1cj4XuHTYpJ52MjiITnif6Wo5" - "vPzI1vhId4n+i8yrwNzDWQQ/STn7jkHen52Z9MGApA3lavKJV4a1sOuw9CK6guvVAeMNOuTb" - "O6Izje9B/sb9K+ctHq4n86rWLnBj7UF4TW8BvU49wVDxNR2POc6fePAtzHvKmoSewM2VDeIT" - "OqzlXJfpol7ocAi2ZxgOQ6n26BHyf6AwPDd9N7znnbtGo87zB8TFBVTkJHDfymFbEvzO7pMn" - "iq6V66dqPlqEw/5FAgdGzyXFFI2G+ys/UI4HD7T6JFvSOZPKHN5zNADwZ6dzDoHsep27BY1H" - "c3bIG0lFlYmZ/p0eLXruPOumEfDt/NxxnE4GjRdG9Vs7TyBMW4x8l97sOTrAOxe0aoL4/Dl3" - "neRXHFmwtHlQAzpYn4HnV8OAh4Sg3UalHtZNBfjptA+/MjyOIXO2dnay8IK19nPPOzzkW+E1" - "3+z25irp1tV1ZtilQK+k4IAH+ldiQPJZsF6tewpO6iOk30SRsV6Cfh5WCzCf94z1aq2Whxfu" - "EyTwOP7wQVYzuJ4Zja4gZP0Es1bzUsut5ZRn8j1//AMvAZPgVbz6DWZ7g14At9rjgBIgeN6F" - "4Facqkb5NoTF/gxCaKVn3INeKZTiy+jG7gxOHjKlqvadpMPY84osKR6r5plRRGsONTVJ9eSJ" - "Sr7h0C7ZXVqtvU9GCKZwTw+1Y8Vcqb7EmV6C1mrT+5FBgDXzi7THMey8U6dD++94E+m9VK5I" - "Mq4L9ZfmTDNDR7z2neCuMfTyFyjfdeMuLdFOm9fJU7V481Sxp5f0Oen9d/pm8dasgi59Tvad" - "Da6ZLN7bVNEVnrpMHQuAyyxQMpgs3q/qDtmgWymvrJHSiGS1Wym3ouc75MXCwvNst7TSQcmc" - "dlt1qHZvyuy0y+oE8h7p8K7G9v1wZc7oNgpHFdE9oJdlij5mSZe8x9pS+ZZpfbrCY22xeL8n" - "fFvt4D3qplVBySugjGH2dMRDrgDdznPrjFS4Tqfz//1fiDjudA7X+38c/wE5II6oZulXWgAA" - "AABJRU5ErkJggg==") - -#---------------------------------------------------------------------- -whidbey_dock_pane_top = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAF0AAABdCAMAAADwr5rxAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR" - "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagaHWVcHiYZ3egZ3e1cHilUHjRQXLw" - "cYCncYa0dpC4R4DwU4PwZobHYIfTcYXGcIjVcpDBc5fWZpHxcZjgcJj3d6Dld6Pwi5Ozl6e3" - "q62xgIjQgpXEgJbUkJjAkJjQgJjggKDXkqHCk6TWhafggqfwh7Dgh7Dwk6Xgk7Tkl7fwoKjA" - "oKjWqLDIp7fXsLDIsbbWoLfnoLjwsLjjl8D4pMLwscHnsMfxtdD0wMHg6tTN4Njk5eTo4Of3" - "5/D48Ofh9/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAaHenigAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAe1SURBVGhDpZkNexJHEMcxrTVNao3G0PoSaXmJ4l1soBhCCUdBmkaPCDFWCN//e1z/" - "M7O7t/fC3aHzPMqFu/3t/2ZnZmeTUrCBnZ83m2cbPB+UNni4NxweHx/9tsGIDei92bBF9B+L" - "44vTu6T8AFb+oTC+ML07gfIjppe/L4ovSofy1nGjIfT9oviC9O6kBZ83flf0ovhi9NccLY2y" - "sv39gvhC9NeT4R/HR5q+Xwa9GL4IvQmvLBcRK4gvQG/+DZcvP8JG2hYF1efTSflxY2HIdLHY" - "gxVwTi696VGCptLz8Xl0Ud4oR90u2vOXNodOyjlYFjoa+VPT89Rn010ol+xXdP1Bq/oI9jA7" - "azPprguX23T4R7QbejY+i/6q1YJXpLYwlZ0foz/4LqOkZdBfvaJgaZQzPbP3IAu/nv7rEYxi" - "g+xgIfVrgX+44FV99HAP7J2dra216jO0/3RULkfpPAP9p+lg37u3Hp65r/oHByE9GvDy/e4u" - "2Bnw7F3bD+kQbGbS1w/y4Dk9wd29vcePtc5dtp9/1rOQ8jt3MjfBnFwlPLtgd2dnG7YD291V" - "88Et2fBU7eNQz2fgiU3kLWVPnhBflHfCRwcpb5GifTw2+M5n4Mkf21vbh7fanvzCPoLy25XB" - "+9MUfJI+v55NuqKjswLw7v3729vPDVounj6ld6Grzi0/6vvTqRplvUOCPie64Dsrot9u3X//" - "PgbHj5VthgPP8BkGDZtx58TpYNODo7cMZ/ri3yQb3/yjv+0EN77QE/gYnZTjuclodH4OONON" - "XV1dXcLic606V7PZdDoaDRP4KH0O4TPaOPHgX1HK9eWE32oy6fXG0VtXRJ/QmDg+Qp8THbqZ" - "PmxGZF+Ty5g+mYzHA+see4X8ksTb9DnRySui3atpBPxlsQk1euvrm+JzQ4/43qIDPhefK7rG" - "86x4d8tGI1/wC7CnfEtpH7asyAnpeMz4fOh5XrfbHfxHgGsY61Ue05h3hs7TGrqFN3R6wdDn" - "RHccpsMr1ywuQWf8Dd3TZPpstUK8prPykEDSnXN+d9Dl1eN0T5Y9hW7wii7K0+hY0ekauseR" - "Y3tF3iFUL3Ra9tUSRhlEn17fcdos7ZIDYkQ3lNH9JSB4P36CPSPDlBk80zmoVp8+faJBZCEd" - "iSJ03LVM0Rl/Sa+8kmQaLpmi8UTngB3J95qONWXtFyqYU+l9zoh0euslyKBLOiToFX7tC4nz" - "4Rr6jbgmph3SW60TxH0p4Npi3klpR7Az3URpjL5iv7suh1UvnX5yFpQ4D8lp2jM0cKnplzoH" - "sugDvNyKVlZTWiewN2/6/RL5hTNf0VcR+gB+4ThfQ2fHGzqGMkXoruOUBr7KEqFzRIbai9Eh" - "YTXheLXorlurlLx3pByrENHu9V0ji5ciTXu/K3FFEtgzEe1us1YrvfOYbejivWJ0FbWGbvzu" - "wmq1drsU9Jgd0iWbvC5rH49ViUrTDsfyNqjpJptaDK+2Kd5fYhFS6JLm2fQK0yldyDOG/obg" - "z55xNgUvaIm131UlQAm+UPFgRlEl0MWGqoxzyjlxk0KvgS65KviidJG4Evop0f0Z+oFInXFE" - "uaIz3qpxqJEw2ZnfYtXVakH6R1pzolMRdar8hNBViWWKU6syXHeprB4mYynLQWe8J/ShTL76" - "KK7xiF5jOu304cZC5UErN3Tx/cmJTe/3WdpAz6Y/aWbPA1ukJ+jkF9XymX1V8BYd8cYt3kBo" - "8g76miOOe705bVzhMFt5qF1Fjv2Y41S4Jxgofkh3MXO1+ifD57S3WMMs5TadnWMe43wQulav" - "6ZSI8AvDb2+79mbedep1iRYxuxdTvicPuW69XpH9A3Z2hopsDMsJn5sWuGmUD4egq2hJ0vXS" - "EhyPGTgprLFitnq99lwWVKwpi9GHRZVHtSvfE5yCygLgst0+hRG7UpFuIYYHvBZVHqeLevJ5" - "9VknisBPp6fVarUdQ9PErB5wlaHpfueiIMWTloZPTbAvXxLzmG8ps3C0cZFDgJs4T1tV/g54" - "nchKve/zzh+z+byHbwQeBFiWuM/jMSMzvnCcw0O5ZPX+9Wx6Ybp1Ncc1dSmo0QpO+HpCecLv" - "xKw4Cg484ESf+r51XkI/j9MCUrRrnVcr1Wro77WewQ0DD4IPH/Rphs4z4/EFTJ+f6Ah5HhJT" - "4Hl/mfggR0Bj1FmZ8xPSyKInlad6xnpMjkQoARqPZnuqW3GuGokDcGSSzN9x6EOu0LHFGguL" - "SyY+i24f5lRvr/t7Xe2Qe06aS9R3GXT6xYI5E+neW21UFv2kth6/nt6LnOQUXW2rZi5IR8Vc" - "i8/Qjr/ShLaGTjXzq7QHAX5/zZ0O7eZMl0aUtnD6TyqSzutU/Zkx04zRCS8NgqKjcFmpVyxX" - "w6ekSzPa5QAQ0pMlNzZBzu/0TJ+TEjNwS0rhKp5NVDGlz2lFOjXq1aKtxZqoydGu8dxlhrYE" - "3LRzX5dNalTYIVv0QsrzqphsJ7pDtulFlBeiJzvk5TI3WuTFc/1u1PPxR3WokXbum/yu8Rz3" - "RO92sYVa7dw308X3mu6kbdCbVwJrhIp7qi1prcXXxrseJ3gqXPF27ts9Q4FJuvlUkLb7p09R" - "KGZkKHdpsOLwYhGphLXbbTqeZ3gifmsD7UHQbh/WNoEH/wMcYo64Ex2PFwAAAABJRU5ErkJg" - "gg==") - -#---------------------------------------------------------------------- -whidbey_left = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB4AAAArCAMAAABYWciOAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAaHWVZ3egZ3e1cHilcYCncYa0dpC4ZobHcYXGcpDBc5fWd6Dld6Pwi5OzgIjQ" - "gJbUkJjQgJjggKDXkqHCk6TWhafggqfwh7Dwk6Xgk7Tkl7fwoKjWqLDIoLfnpMLwscHnsMfx" - "tdD04Njk5/D49/f3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAQ3JLMwAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAF4SURBVDhPfdTbdoIwEAVQL6htAi0tElBaoVb+/xPTM5M7wc6LLvc6GTIJbnRel/DT" - "ZkUvwXOefsahdqGMJ2LvSwaO4P7d5BdMWejQ9+dzzhOiY4/quu4z44kYSebudbH4REwLm7Q6" - "Jr2hk+lrGR4e7Rb17ZRSdV23v55vxL4vsRCBOesXRrquBbZm0yb7jIHD/EDNKPpUjRBvbmOU" - "Heb7/f6g/aISJhz6R8J4MJvmbM6FGSrPmRaM09i0YZ4zDdHxTN8909I8RMtzyu3NztgwbyxK" - "qytlq6pK0qqROC/0vipGzx0v7ll/MAY2Y1G1SWv9UpXlCvNlpiPZlyjX2w4VJ/rlZk7+D3Oe" - "DsoXwqoNV5HzKHtidJlUC3eXifuXZcxNE91U4xFLIb6jm8oeWIKLcFPN/jxLKY/HhM3+TUl5" - "OhU48eQN9Y6VTwe6D+kLbJ0W3m5X3m926ntgXb7+eg/z2ZzJhcuusN4Lsds9/WfSuhBes94U" - "C6r/AM3yZVcU56/qAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -whidbey_left_single = whidbey_left - -#---------------------------------------------------------------------- -whidbey_left_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB4AAAArCAMAAABYWciOAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR" - "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagcHiYZ3egcHilUHjRQXLwR4DwU4Pw" - "YIfTcYXGcIjVc5fWZpHxcJj3d6PwgJbUkJjAkJjQkqHChafggqfwh7Dgh7Dwl7fwoKjAqLDI" - "sLDIl8D4pMLw4Of35/D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAQS37pgAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAGNSURBVDhPfdRrW8IgFAdwLyuXZLIUy67D6dK0pd3w+38xOuewAYOMN3ue/fbnwHZG" - "R8ej5251Yu33nMfcHw8H1iNOxsiNh5xkGUfvmqIBg2YZ8KBrvM3J5BoGH7NBnW9xMjHMGTjl" - "fQYlxvKYh/V5jErc5MEdJxMOAx/BKxZI0w/LkI340aZx5jZzdmdrU92TjKr8IbB2szHKqv1+" - "r2Y4hFDINzWf082A2Xxu+II0TDNU4KcnAcNPz4TiV0P6pp1XKduM9R0XZdlipXBpnNXpgGl3" - "Hu+qdSnzZ1sb0libpab2rqrKMs/d0tqstz+QhwfUt/dabFrrbYXzy1OsNwf0Fgs2TB+ad77B" - "6SNOba9B/uV49D6ZqIvX3bJp1m++mEBO710rLg8wv8wNmVZj6ZdrxeWatmcZW9FjXbxj3ufR" - "6NPr8wLyHnM28vtc6+INX08+w9LTKednwS9I+TwnJg3+UMoTGw3/7wKndxqyXq3gAdg9ZaO0" - "1oab8yo+mRYLKe1p9se5tpCX/7G+dUfhL8vucupsrDz0AAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -whidbey_left_focus_single = whidbey_left_focus - -#---------------------------------------------------------------------- -whidbey_right = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB4AAAArCAMAAABYWciOAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAaHWVcHilcYCncYa0dpC4ZobHcYXGcpDBc5fWcZjgd6Dld6Pwi5OzgJbUkJjA" - "kJjQgKDXk6TWhafggqfwh7Dwl7fwp7fXoLfnoLjwsLjjpMLwscHntdD0wMHg4Of35/D49/f3" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAWZqHkAAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAFySURBVDhPddPbeoIwDABglDqoFDcVGBVw8P4PyXJoQ0sxN+L3m0NDzVaJx/YoT5k8" - "9fbAhfve2luS77kfhq5rir077pkTZ34Ng7Vt2yRO/ELuUPeOTIWxdOrA3Fc46p/9AVobsgnm" - "Z0b1xRsTeLa+EV1f+jCBQ+8DlnzgsDBX2fLxYFR8WeYtxJF/u65tF95KM0/TNEv+ZzZfkElL" - "TbKhuDEVnJ/4Z1+cufpmfsBwC47newNV1fV6v8cMTqMx67Jkhs0s3YIRsNbqHDCePczWhVIx" - "S28NoVRdRyxrMaR5zZPjdcDJha+opxOf+33ACthtrR/glkY7LzmXs5npjbn3VqqcFHmE2i0E" - "934+fd9PjKXdvylbR7yn/q7FuVB8HOF9uMJUOsjF3retb9PcysuFZ+aA0QrJJXYzC6/Fk+IO" - "Eee628IOquJcx5wP6nYV9cYvGpYBKucNRqNHpfW+r9+580uS63vjD855vvXcF4fvB7r+A9+i" - "Xf4K/oDaAAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -whidbey_right_single = whidbey_right - -#---------------------------------------------------------------------- -whidbey_right_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAAB4AAAArCAMAAABYWciOAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR" - "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagcHiYZ3egcHilUHjRQXLwR4DwU4Pw" - "YIfTcYXGcIjVc5fWZpHxcJj3d6PwgJbUkJjAkJjQkqHChafggqfwh7Dgh7Dwl7fwoKjAqLDI" - "sLDIl8D4pMLw4Of35/D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAQS37pgAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAGXSURBVDhPdZTZVoNADEDpaC2CFSqC1hVaxWoVqdv0/39szDIraF7gcHuTTCankbJx" - "6V7tW2TfTprVmDvcNKsxt7ismnbzOPQ1npaMh5zxNMdo4Afr0CfMNK8Bv4UcMdBzwshDHzBS" - "wlWN6QM/UmKecu68hBj40ed8nmrOuN28u/qR+op9XNfANw+mf8asow31ge8Mh9au4zhlRIF+" - "1z2zjwcTiKWL/f6p2zFHHMdJWkpty77/lpCffcQ3IwzHY5+GitkDG8fTddv/MB2v+9n6dlVJ" - "aBxq9/Dk/l+95IDgu8b3eD0GJ1ibTmYwzqFt12wTLn07xKc51XW16XqaF20D1jPVtRHf3XHn" - "Sxyqm1ovC5r+MZ97OcJEj/TULuA+B3ZRFIdm5njd/o1JaSgmvzK7Bh8LXAt8kku1/8KaAr61" - "u+ZsQ1X0Aauks1tsKdhCzGb4gzMKr66uTTzLFwuNnctjmUycb3t2m6om7JPtu3qZyE+yBURI" - "+UogvwAM5QfUYOw/ybIhtVghPuBUXrg/LiHG1NmwcSNXqV+4tHLqnJPo+QAAAABJRU5ErkJg" - "gg==") - -#---------------------------------------------------------------------- -whidbey_right_focus_single = whidbey_right_focus - -#---------------------------------------------------------------------- -whidbey_up = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACsAAAAeCAMAAACCNBfsAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAaHWVcHilcYCncYa0dpC4ZobHcYXGcpDBc5fWcZjgd6Dld6Pwi5OzgJbUkJjA" - "kJjQgKDXk6TWhafggqfwh7Dwl7fwp7fXoLfnoLjwsLjjpMLwscHntdD0wMHg4Of35/D49/f3" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAWZqHkAAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAFmSURBVDhPhdTtdoMgDAZgW3GKWjsL2i/X2vu/SJaEBBXcWf6Jz3l5i9bMpdNXR3Xa" - "Wc/StXNfKXXawaktm1rrUuWHJCWxX01TA1bqkODYlm3bNjCAVYwji9TbneStJcoWcNR5Yz0V" - "mySvLVJrvW/buq7g7NadVxbpvJ3taSyWUuef9cx6kxwsdU3sprPY0tJEucboqginwZapjfqC" - "1UUhT9BboXb28Twfa42pQjLZQMUCwiHbdZKMdqFsPx+PeZee3w2w3WpXugvUY7GAsXPmLvdx" - "HITzXe4QbK8Klbvsckcr+C/bF0WeZ+52ez6Bw+D2AwxdwAxwhRsaPDp9hA4OLWGpSn1pVlZh" - "X8Cg2dpNLlxwrgFKFpP/sRqZf26Ph3T2Te8w3AyijSlJ8fuA1v/Acfy+0Dxp8DyZig2dr9fw" - "WXj5ExoGnxpy5TSi78c0gRUacvE0XjvfsGnqwuryH3q/d6hz07L6CxOEXf5LAPv7AAAAAElF" - "TkSuQmCC") - -#---------------------------------------------------------------------- -whidbey_up_single = whidbey_up - -#---------------------------------------------------------------------- -whidbey_up_focus = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAACsAAAAeCAMAAACCNBfsAAAAAXNSR0IArs4c6QAAAARnQU1B" - "AACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAA" - "AwBQTFRFAAAAECBXFC9vECiQBS2oIDKMIDigC0CVJUqQIkewJFKlJlayMEiwMlSiK2G0JFTR" - "LmnSKGHmKHDoInDwMGjgNnDgNXLwSFeKQFizR2OkUGagcHiYZ3egcHilUHjRQXLwR4DwU4Pw" - "YIfTcYXGcIjVc5fWZpHxcJj3d6PwgJbUkJjAkJjQkqHChafggqfwh7Dgh7Dwl7fwoKjAqLDI" - "sLDIl8D4pMLw4Of35/D4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAQS37pgAAAQB0Uk5T////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////////////////////////////////////////////////////////" - "////////////////////AFP3ByUAAAAYdEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My4zNqnn" - "4iUAAAGTSURBVDhPfdQNV4IwFAZgpEyCVBRZaR8OUcI0yrLw//8xuvfuy22e7jkKZz68uxtg" - "0Pm135fl24XxwB/bNU1VFS/+D77d/TY12lsPe3aLqTkUu3Gxa7cHSC3IsmsHOxZS64pzYTMH" - "23Z7qKFXvpTWwZZd0w5wJivLbHxu14fmtSqUzRhYC5/ZEuY/tVbZ2NjyA1o9/UB9qmrtZG0x" - "teKtdnjSplCmDWXLd7xZF63G0opUzux2Ra5eoLCYShvQqv2io7IymewGUsV9lVYdcG1TqAnd" - "QbSbDbR6bqETkastYbCruob5xTNAhpp27PgK7WqFG8DZvz2kY8DBQwGF68XKW/HUtPCBE1rb" - "dJKCjOMwDLq7gjHbkscvZUEOBiGtLc+NtTdYjCcJyFDsQ2cshOnr1PlYUmH7aTqbqYyEajRS" - "12Bqr6f2V2CaLInjCCqGShJ5NTRAVOQSRokulDWfozap2gLGmaMwetIv7/yeulGpxnb94TCK" - "Hp23fLHAedSgeS/C4fHo/y89R5qqfhF9+xJGvszoH5Xccuo6pVT3AAAAAElFTkSuQmCC") - -#---------------------------------------------------------------------- -whidbey_up_focus_single = whidbey_up_focus - -#---------------------------------------------------------------------- - -whidbey_denied = aero_denied - -#---------------------------------------------------------------------- - -# ------------------------ # -# - AuiToolBar Constants - # -# ------------------------ # - -ITEM_CONTROL = wx.ITEM_MAX -""" The item in the AuiToolBar is a control. """ -ITEM_LABEL = ITEM_CONTROL + 1 -""" The item in the AuiToolBar is a text label. """ -ITEM_SPACER = ITEM_CONTROL + 2 -""" The item in the AuiToolBar is a spacer. """ -ITEM_SEPARATOR = wx.ITEM_SEPARATOR -""" The item in the AuiToolBar is a separator. """ -ITEM_CHECK = wx.ITEM_CHECK -""" The item in the AuiToolBar is a toolbar check item. """ -ITEM_NORMAL = wx.ITEM_NORMAL -""" The item in the AuiToolBar is a standard toolbar item. """ -ITEM_RADIO = wx.ITEM_RADIO -""" The item in the AuiToolBar is a toolbar radio item. """ -ID_RESTORE_FRAME = wx.ID_HIGHEST + 10000 -""" Identifier for restoring a minimized pane. """ - -BUTTON_DROPDOWN_WIDTH = 10 -""" Width of the drop-down button in AuiToolBar. """ - -DISABLED_TEXT_GREY_HUE = 153.0 -""" Hue text colour for the disabled text in AuiToolBar. """ -DISABLED_TEXT_COLOUR = wx.Colour(DISABLED_TEXT_GREY_HUE, - DISABLED_TEXT_GREY_HUE, - DISABLED_TEXT_GREY_HUE) -""" Text colour for the disabled text in AuiToolBar. """ - -AUI_TB_TEXT = 1 << 0 -""" Shows the text in the toolbar buttons; by default only icons are shown. """ -AUI_TB_NO_TOOLTIPS = 1 << 1 -""" Don't show tooltips on `AuiToolBar` items. """ -AUI_TB_NO_AUTORESIZE = 1 << 2 -""" Do not auto-resize the `AuiToolBar`. """ -AUI_TB_GRIPPER = 1 << 3 -""" Shows a gripper on the `AuiToolBar`. """ -AUI_TB_OVERFLOW = 1 << 4 -""" The `AuiToolBar` can contain overflow items. """ -AUI_TB_VERTICAL = 1 << 5 -""" The `AuiToolBar` is vertical. """ -AUI_TB_HORZ_LAYOUT = 1 << 6 -""" Shows the text and the icons alongside, not vertically stacked. -This style must be used with ``AUI_TB_TEXT``. """ -AUI_TB_PLAIN_BACKGROUND = 1 << 7 -""" Don't draw a gradient background on the toolbar. """ -AUI_TB_CLOCKWISE = 1 << 8 -AUI_TB_COUNTERCLOCKWISE = 1 << 9 - -AUI_TB_HORZ_TEXT = AUI_TB_HORZ_LAYOUT | AUI_TB_TEXT -""" Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT``. """ -AUI_TB_VERT_TEXT = AUI_TB_VERTICAL | AUI_TB_CLOCKWISE | AUI_TB_TEXT - -AUI_TB_DEFAULT_STYLE = 0 -""" `AuiToolBar` default style. """ - -# AuiToolBar settings -AUI_TBART_SEPARATOR_SIZE = 0 -""" Separator size in AuiToolBar. """ -AUI_TBART_GRIPPER_SIZE = 1 -""" Gripper size in AuiToolBar. """ -AUI_TBART_OVERFLOW_SIZE = 2 -""" Overflow button size in AuiToolBar. """ - -# AuiToolBar text orientation -AUI_TBTOOL_TEXT_LEFT = 0 # unused/unimplemented -""" Text in AuiToolBar items is aligned left. """ -AUI_TBTOOL_TEXT_RIGHT = 1 -""" Text in AuiToolBar items is aligned right. """ -AUI_TBTOOL_TEXT_TOP = 2 # unused/unimplemented -""" Text in AuiToolBar items is aligned top. """ -AUI_TBTOOL_TEXT_BOTTOM = 3 -""" Text in AuiToolBar items is aligned bottom. """ - -# AuiToolBar tool orientation -AUI_TBTOOL_HORIZONTAL = 0 # standard -AUI_TBTOOL_VERT_CLOCKWISE = 1 # rotation of 90 on the right -AUI_TBTOOL_VERT_COUNTERCLOCKWISE = 2 # rotation of 90 on the left - - -# --------------------- # -# - AuiMDI* Constants - # -# --------------------- # - -wxWINDOWCLOSE = 4001 -""" Identifier for the AuiMDI "close window" menu. """ -wxWINDOWCLOSEALL = 4002 -""" Identifier for the AuiMDI "close all windows" menu. """ -wxWINDOWNEXT = 4003 -""" Identifier for the AuiMDI "next window" menu. """ -wxWINDOWPREV = 4004 -""" Identifier for the AuiMDI "previous window" menu. """ - -# ----------------------------- # -# - AuiDockingGuide Constants - # -# ----------------------------- # - -colourTargetBorder = wx.Colour(180, 180, 180) -colourTargetShade = wx.Colour(206, 206, 206) -colourTargetBackground = wx.Colour(224, 224, 224) -colourIconBorder = wx.Colour(82, 65, 156) -colourIconBackground = wx.Colour(255, 255, 255) -colourIconDockingPart1 = wx.Colour(215, 228, 243) -colourIconDockingPart2 = wx.Colour(180, 201, 225) -colourIconShadow = wx.Colour(198, 198, 198) -colourIconArrow = wx.Colour(77, 79, 170) -colourHintBackground = wx.Colour(0, 64, 255) -guideSizeX, guideSizeY = 29, 32 -aeroguideSizeX, aeroguideSizeY = 31, 32 -whidbeySizeX, whidbeySizeY = 43, 30 - -# ------------------------------- # -# - AuiSwitcherDialog Constants - # -# ------------------------------- # - -SWITCHER_TEXT_MARGIN_X = 4 -SWITCHER_TEXT_MARGIN_Y = 1 diff --git a/enaml/wx/wx_upstream/aui/aui_switcherdialog.py b/enaml/wx/wx_upstream/aui/aui_switcherdialog.py deleted file mode 100644 index 4cf3923af..000000000 --- a/enaml/wx/wx_upstream/aui/aui_switcherdialog.py +++ /dev/null @@ -1,1215 +0,0 @@ -""" -Description -=========== - -The idea of `SwitcherDialog` is to make it easier to implement keyboard -navigation in AUI and other applications that have multiple panes and -tabs. - -A key combination with a modifier (such as ``Ctrl`` + ``Tab``) shows the -dialog, and the user holds down the modifier whilst navigating with -``Tab`` and arrow keys before releasing the modifier to dismiss the dialog -and activate the selected pane. - -The switcher dialog is a multi-column menu with no scrolling, implemented -by the :class:`MultiColumnListCtrl` class. You can have headings for your items -for logical grouping, and you can force a column break if you need to. - -The modifier used for invoking and dismissing the dialog can be customised, -as can the colours, number of rows, and the key used for cycling through -the items. So you can use different keys on different platforms if -required (especially since ``Ctrl`` + ``Tab`` is reserved on some platforms). - -Items are shown as names and optional 16x16 images. - - -Base Functionalities -==================== - -To use the dialog, you set up the items in a `SwitcherItems` object, -before passing this to the `SwitcherDialog` instance. - -Call :meth:`SwitcherItems.AddItem` and optionally :meth:`SwitcherItems.AddGroup` -to add items and headings. These functions take a label (to be displayed to the user), -an identifying name, an integer id, and a bitmap. The name and id are purely for -application-defined identification. You may also set a description to be displayed -when each item is selected; and you can set a window pointer for convenience when -activating the desired window after the dialog returns. - -Have created the dialog, you call :meth:`~Dialog.ShowModal`, and if the return value is -``wx.ID_OK``, retrieve the selection from the dialog and activate the pane. - -The sample code below shows a generic method of finding panes and notebook -tabs within the current :class:`~lib.agw.aui.framemanager.AuiManager`, and using the pane name or notebook -tab position to display the pane. - -The only other code to add is a menu item with the desired accelerator, -whose modifier matches the one you pass to :meth:`SwitcherDialog.SetModifierKey` -(the default being ``wx.WXK_CONTROL``). - - -Usage -===== - -Menu item:: - - if wx.Platform == "__WXMAC__": - switcherAccel = "Alt+Tab" - elif wx.Platform == "__WXGTK__": - switcherAccel = "Ctrl+/" - else: - switcherAccel = "Ctrl+Tab" - - view_menu.Append(ID_SwitchPane, _("S&witch Window...") + "\t" + switcherAccel) - - -Event handler:: - - def OnSwitchPane(self, event): - - items = SwitcherItems() - items.SetRowCount(12) - - # Add the main windows and toolbars, in two separate columns - # We'll use the item 'id' to store the notebook selection, or -1 if not a page - - for k in xrange(2): - if k == 0: - items.AddGroup(_("Main Windows"), "mainwindows") - else: - items.AddGroup(_("Toolbars"), "toolbars").BreakColumn() - - for pane in self._mgr.GetAllPanes(): - name = pane.name - caption = pane.caption - - toolbar = isinstance(info.window, wx.ToolBar) or isinstance(info.window, aui.AuiToolBar) - if caption and (toolBar and k == 1) or (not toolBar and k == 0): - items.AddItem(caption, name, -1).SetWindow(pane.window) - - # Now add the wxAuiNotebook pages - - items.AddGroup(_("Notebook Pages"), "pages").BreakColumn() - - for pane in self._mgr.GetAllPanes(): - nb = pane.window - if isinstance(nb, aui.AuiNotebook): - for j in xrange(nb.GetPageCount()): - - name = nb.GetPageText(j) - win = nb.GetPage(j) - - items.AddItem(name, name, j, nb.GetPageBitmap(j)).SetWindow(win) - - # Select the focused window - - idx = items.GetIndexForFocus() - if idx != wx.NOT_FOUND: - items.SetSelection(idx) - - if wx.Platform == "__WXMAC__": - items.SetBackgroundColour(wx.WHITE) - - # Show the switcher dialog - - dlg = SwitcherDialog(items, wx.GetApp().GetTopWindow()) - - # In GTK+ we can't use Ctrl+Tab; we use Ctrl+/ instead and tell the switcher - # to treat / in the same was as tab (i.e. cycle through the names) - - if wx.Platform == "__WXGTK__": - dlg.SetExtraNavigationKey(wxT('/')) - - if wx.Platform == "__WXMAC__": - dlg.SetBackgroundColour(wx.WHITE) - dlg.SetModifierKey(wx.WXK_ALT) - - ans = dlg.ShowModal() - - if ans == wx.ID_OK and dlg.GetSelection() != -1: - item = items.GetItem(dlg.GetSelection()) - - if item.GetId() == -1: - info = self._mgr.GetPane(item.GetName()) - info.Show() - self._mgr.Update() - info.window.SetFocus() - - else: - nb = item.GetWindow().GetParent() - win = item.GetWindow(); - if isinstance(nb, aui.AuiNotebook): - nb.SetSelection(item.GetId()) - win.SetFocus() - - -""" - -import wx - -import auibook -from aui_utilities import FindFocusDescendant -from aui_constants import SWITCHER_TEXT_MARGIN_X, SWITCHER_TEXT_MARGIN_Y - - -# Define a translation function -_ = wx.GetTranslation - - -class SwitcherItem(object): - """ An object containing information about one item. """ - - def __init__(self, item=None): - """ Default class constructor. """ - - self._id = 0 - self._isGroup = False - self._breakColumn = False - self._rowPos = 0 - self._colPos = 0 - self._window = None - self._description = "" - - self._textColour = wx.NullColour - self._bitmap = wx.NullBitmap - self._font = wx.NullFont - - if item: - self.Copy(item) - - - def Copy(self, item): - """ - Copy operator between 2 :class:`SwitcherItem` instances. - - :param `item`: another instance of :class:`SwitcherItem`. - """ - - self._id = item._id - self._name = item._name - self._title = item._title - self._isGroup = item._isGroup - self._breakColumn = item._breakColumn - self._rect = item._rect - self._font = item._font - self._textColour = item._textColour - self._bitmap = item._bitmap - self._description = item._description - self._rowPos = item._rowPos - self._colPos = item._colPos - self._window = item._window - - - def SetTitle(self, title): - - self._title = title - return self - - - def GetTitle(self): - - return self._title - - - def SetName(self, name): - - self._name = name - return self - - - def GetName(self): - - return self._name - - - def SetDescription(self, descr): - - self._description = descr - return self - - - def GetDescription(self): - - return self._description - - - def SetId(self, id): - - self._id = id - return self - - - def GetId(self): - - return self._id - - - def SetIsGroup(self, isGroup): - - self._isGroup = isGroup - return self - - - def GetIsGroup(self): - - return self._isGroup - - - def BreakColumn(self, breakCol=True): - - self._breakColumn = breakCol - return self - - - def GetBreakColumn(self): - - return self._breakColumn - - - def SetRect(self, rect): - - self._rect = rect - return self - - - def GetRect(self): - - return self._rect - - - def SetTextColour(self, colour): - - self._textColour = colour - return self - - - def GetTextColour(self): - - return self._textColour - - - def SetFont(self, font): - - self._font = font - return self - - - def GetFont(self): - - return self._font - - - def SetBitmap(self, bitmap): - - self._bitmap = bitmap - return self - - - def GetBitmap(self): - - return self._bitmap - - - def SetRowPos(self, pos): - - self._rowPos = pos - return self - - - def GetRowPos(self): - - return self._rowPos - - - def SetColPos(self, pos): - - self._colPos = pos - return self - - - def GetColPos(self): - - return self._colPos - - - def SetWindow(self, win): - - self._window = win - return self - - - def GetWindow(self): - - return self._window - - -class SwitcherItems(object): - """ An object containing switcher items. """ - - def __init__(self, items=None): - """ Default class constructor. """ - - self._selection = -1 - self._rowCount = 10 - self._columnCount = 0 - - self._backgroundColour = wx.NullColour - self._textColour = wx.NullColour - self._selectionColour = wx.NullColour - self._selectionOutlineColour = wx.NullColour - self._itemFont = wx.NullFont - - self._items = [] - - if wx.Platform == "__WXMSW__": - # If on Windows XP/Vista, use more appropriate colours - self.SetSelectionOutlineColour(wx.Colour(49, 106, 197)) - self.SetSelectionColour(wx.Colour(193, 210, 238)) - - if items: - self.Copy(items) - - - def Copy(self, items): - """ - Copy operator between 2 :class:`SwitcherItems`. - - :param `items`: another instance of :class:`SwitcherItems`. - """ - - self.Clear() - - for item in items._items: - self._items.append(item) - - self._selection = items._selection - self._rowCount = items._rowCount - self._columnCount = items._columnCount - - self._backgroundColour = items._backgroundColour - self._textColour = items._textColour - self._selectionColour = items._selectionColour - self._selectionOutlineColour = items._selectionOutlineColour - self._itemFont = items._itemFont - - - def AddItem(self, titleOrItem, name=None, id=0, bitmap=wx.NullBitmap): - - if isinstance(titleOrItem, SwitcherItem): - self._items.append(titleOrItem) - return self._items[-1] - - item = SwitcherItem() - item.SetTitle(titleOrItem) - item.SetName(name) - item.SetId(id) - item.SetBitmap(bitmap) - - self._items.append(item) - return self._items[-1] - - - def AddGroup(self, title, name, id=0, bitmap=wx.NullBitmap): - - item = self.AddItem(title, name, id, bitmap) - item.SetIsGroup(True) - - return item - - - def Clear(self): - - self._items = [] - - - def FindItemByName(self, name): - - for i in xrange(len(self._items)): - if self._items[i].GetName() == name: - return i - - return wx.NOT_FOUND - - - def FindItemById(self, id): - - for i in xrange(len(self._items)): - if self._items[i].GetId() == id: - return i - - return wx.NOT_FOUND - - - def SetSelection(self, sel): - - self._selection = sel - - - def SetSelectionByName(self, name): - - idx = self.FindItemByName(name) - if idx != wx.NOT_FOUND: - self.SetSelection(idx) - - - def GetSelection(self): - - return self._selection - - - def GetItem(self, i): - - return self._items[i] - - - def GetItemCount(self): - - return len(self._items) - - - def SetRowCount(self, rows): - - self._rowCount = rows - - - def GetRowCount(self): - - return self._rowCount - - - def SetColumnCount(self, cols): - - self._columnCount = cols - - - def GetColumnCount(self): - - return self._columnCount - - - def SetBackgroundColour(self, colour): - - self._backgroundColour = colour - - - def GetBackgroundColour(self): - - return self._backgroundColour - - - def SetTextColour(self, colour): - - self._textColour = colour - - - def GetTextColour(self): - - return self._textColour - - - def SetSelectionColour(self, colour): - - self._selectionColour = colour - - - def GetSelectionColour(self): - - return self._selectionColour - - - def SetSelectionOutlineColour(self, colour): - - self._selectionOutlineColour = colour - - - def GetSelectionOutlineColour(self): - - return self._selectionOutlineColour - - - def SetItemFont(self, font): - - self._itemFont = font - - - def GetItemFont(self): - - return self._itemFont - - - def PaintItems(self, dc, win): - - backgroundColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE) - standardTextColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) - selectionColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT) - selectionOutlineColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) - standardFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) - groupFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) - groupFont.SetWeight(wx.BOLD) - - if self.GetBackgroundColour().IsOk(): - backgroundColour = self.GetBackgroundColour() - - if self.GetTextColour().IsOk(): - standardTextColour = self.GetTextColour() - - if self.GetSelectionColour().IsOk(): - selectionColour = self.GetSelectionColour() - - if self.GetSelectionOutlineColour().IsOk(): - selectionOutlineColour = self.GetSelectionOutlineColour() - - if self.GetItemFont().IsOk(): - - standardFont = self.GetItemFont() - groupFont = wx.Font(standardFont.GetPointSize(), standardFont.GetFamily(), standardFont.GetStyle(), - wx.BOLD, standardFont.GetUnderlined(), standardFont.GetFaceName()) - - textMarginX = SWITCHER_TEXT_MARGIN_X - - dc.SetLogicalFunction(wx.COPY) - dc.SetBrush(wx.Brush(backgroundColour)) - dc.SetPen(wx.TRANSPARENT_PEN) - dc.DrawRectangleRect(win.GetClientRect()) - dc.SetBackgroundMode(wx.TRANSPARENT) - - for i in xrange(len(self._items)): - item = self._items[i] - if i == self._selection: - dc.SetPen(wx.Pen(selectionOutlineColour)) - dc.SetBrush(wx.Brush(selectionColour)) - dc.DrawRectangleRect(item.GetRect()) - - clippingRect = wx.Rect(*item.GetRect()) - clippingRect.Deflate(1, 1) - - dc.SetClippingRect(clippingRect) - - if item.GetTextColour().IsOk(): - dc.SetTextForeground(item.GetTextColour()) - else: - dc.SetTextForeground(standardTextColour) - - if item.GetFont().IsOk(): - dc.SetFont(item.GetFont()) - else: - if item.GetIsGroup(): - dc.SetFont(groupFont) - else: - dc.SetFont(standardFont) - - w, h = dc.GetTextExtent(item.GetTitle()) - x = item.GetRect().x - - x += textMarginX - - if not item.GetIsGroup(): - if item.GetBitmap().IsOk() and item.GetBitmap().GetWidth() <= 16 \ - and item.GetBitmap().GetHeight() <= 16: - x -= textMarginX - dc.DrawBitmap(item.GetBitmap(), x, item.GetRect().y + \ - (item.GetRect().height - item.GetBitmap().GetHeight())/2, - True) - x += 16 + textMarginX - #x += textMarginX - - y = item.GetRect().y + (item.GetRect().height - h)/2 - dc.DrawText(item.GetTitle(), x, y) - dc.DestroyClippingRegion() - - - def CalculateItemSize(self, dc): - - # Start off allowing for an icon - sz = wx.Size(150, 16) - standardFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) - groupFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) - groupFont.SetWeight(wx.BOLD) - - textMarginX = SWITCHER_TEXT_MARGIN_X - textMarginY = SWITCHER_TEXT_MARGIN_Y - maxWidth = 300 - maxHeight = 40 - - if self.GetItemFont().IsOk(): - standardFont = self.GetItemFont() - - for item in self._items: - if item.GetFont().IsOk(): - dc.SetFont(item.GetFont()) - else: - if item.GetIsGroup(): - dc.SetFont(groupFont) - else: - dc.SetFont(standardFont) - - w, h = dc.GetTextExtent(item.GetTitle()) - w += 16 + 2*textMarginX - - if w > sz.x: - sz.x = min(w, maxWidth) - if h > sz.y: - sz.y = min(h, maxHeight) - - if sz == wx.Size(16, 16): - sz = wx.Size(100, 25) - else: - sz.x += textMarginX*2 - sz.y += textMarginY*2 - - return sz - - - def GetIndexForFocus(self): - - for i, item in enumerate(self._items): - if item.GetWindow(): - - if FindFocusDescendant(item.GetWindow()): - return i - - return wx.NOT_FOUND - - -class MultiColumnListCtrl(wx.PyControl): - """ A control for displaying several columns (not scrollable). """ - - def __init__(self, parent, aui_manager, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, - style=0, validator=wx.DefaultValidator, name="MultiColumnListCtrl"): - - wx.PyControl.__init__(self, parent, id, pos, size, style, validator, name) - - self._overallSize = wx.Size(200, 100) - self._modifierKey = wx.WXK_CONTROL - self._extraNavigationKey = 0 - self._aui_manager = aui_manager - - self.SetInitialSize(size) - self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) - - self.Bind(wx.EVT_PAINT, self.OnPaint) - self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) - self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent) - self.Bind(wx.EVT_CHAR, self.OnChar) - self.Bind(wx.EVT_KEY_DOWN, self.OnKey) - self.Bind(wx.EVT_KEY_UP, self.OnKey) - - - def __del__(self): - - self._aui_manager.HideHint() - - - def DoGetBestSize(self): - - return self._overallSize - - - def OnEraseBackground(self, event): - - pass - - - def OnPaint(self, event): - - dc = wx.AutoBufferedPaintDC(self) - rect = self.GetClientRect() - - if self._items.GetColumnCount() == 0: - self.CalculateLayout(dc) - - if self._items.GetColumnCount() == 0: - return - - self._items.PaintItems(dc, self) - - - def OnMouseEvent(self, event): - - if event.LeftDown(): - self.SetFocus() - - - def OnChar(self, event): - - event.Skip() - - - def OnKey(self, event): - - if event.GetEventType() == wx.wxEVT_KEY_UP: - if event.GetKeyCode() == self.GetModifierKey(): - topLevel = wx.GetTopLevelParent(self) - closeEvent = wx.CloseEvent(wx.wxEVT_CLOSE_WINDOW, topLevel.GetId()) - closeEvent.SetEventObject(topLevel) - closeEvent.SetCanVeto(False) - - topLevel.GetEventHandler().ProcessEvent(closeEvent) - return - - event.Skip() - return - - keyCode = event.GetKeyCode() - - if keyCode in [wx.WXK_ESCAPE, wx.WXK_RETURN]: - if keyCode == wx.WXK_ESCAPE: - self._items.SetSelection(-1) - - topLevel = wx.GetTopLevelParent(self) - closeEvent = wx.CloseEvent(wx.wxEVT_CLOSE_WINDOW, topLevel.GetId()) - closeEvent.SetEventObject(topLevel) - closeEvent.SetCanVeto(False) - - topLevel.GetEventHandler().ProcessEvent(closeEvent) - return - - elif keyCode in [wx.WXK_TAB, self.GetExtraNavigationKey()]: - if event.ShiftDown(): - - self._items.SetSelection(self._items.GetSelection() - 1) - if self._items.GetSelection() < 0: - self._items.SetSelection(self._items.GetItemCount() - 1) - - self.AdvanceToNextSelectableItem(-1) - - else: - - self._items.SetSelection(self._items.GetSelection() + 1) - if self._items.GetSelection() >= self._items.GetItemCount(): - self._items.SetSelection(0) - - self.AdvanceToNextSelectableItem(1) - - self.GenerateSelectionEvent() - self.Refresh() - - elif keyCode in [wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN]: - self._items.SetSelection(self._items.GetSelection() + 1) - if self._items.GetSelection() >= self._items.GetItemCount(): - self._items.SetSelection(0) - - self.AdvanceToNextSelectableItem(1) - self.GenerateSelectionEvent() - self.Refresh() - - elif keyCode in [wx.WXK_UP, wx.WXK_NUMPAD_UP]: - self._items.SetSelection(self._items.GetSelection() - 1) - if self._items.GetSelection() < 0: - self._items.SetSelection(self._items.GetItemCount() - 1) - - self.AdvanceToNextSelectableItem(-1) - self.GenerateSelectionEvent() - self.Refresh() - - elif keyCode in [wx.WXK_HOME, wx.WXK_NUMPAD_HOME]: - self._items.SetSelection(0) - self.AdvanceToNextSelectableItem(1) - self.GenerateSelectionEvent() - self.Refresh() - - elif keyCode in [wx.WXK_END, wx.WXK_NUMPAD_END]: - self._items.SetSelection(self._items.GetItemCount() - 1) - self.AdvanceToNextSelectableItem(-1) - self.GenerateSelectionEvent() - self.Refresh() - - elif keyCode in [wx.WXK_LEFT, wx.WXK_NUMPAD_LEFT]: - item = self._items.GetItem(self._items.GetSelection()) - - row = item.GetRowPos() - newCol = item.GetColPos() - 1 - if newCol < 0: - newCol = self._items.GetColumnCount() - 1 - - # Find the first item from the end whose row matches and whose column is equal or lower - for i in xrange(self._items.GetItemCount()-1, -1, -1): - item2 = self._items.GetItem(i) - if item2.GetColPos() == newCol and item2.GetRowPos() <= row: - self._items.SetSelection(i) - break - - self.AdvanceToNextSelectableItem(-1) - self.GenerateSelectionEvent() - self.Refresh() - - elif keyCode in [wx.WXK_RIGHT, wx.WXK_NUMPAD_RIGHT]: - item = self._items.GetItem(self._items.GetSelection()) - - row = item.GetRowPos() - newCol = item.GetColPos() + 1 - if newCol >= self._items.GetColumnCount(): - newCol = 0 - - # Find the first item from the end whose row matches and whose column is equal or lower - for i in xrange(self._items.GetItemCount()-1, -1, -1): - item2 = self._items.GetItem(i) - if item2.GetColPos() == newCol and item2.GetRowPos() <= row: - self._items.SetSelection(i) - break - - self.AdvanceToNextSelectableItem(1) - self.GenerateSelectionEvent() - self.Refresh() - - else: - event.Skip() - - - def AdvanceToNextSelectableItem(self, direction): - - if self._items.GetItemCount() < 2: - return - - if self._items.GetSelection() == -1: - self._items.SetSelection(0) - - oldSel = self._items.GetSelection() - - while 1: - - if self._items.GetItem(self._items.GetSelection()).GetIsGroup(): - - self._items.SetSelection(self._items.GetSelection() + direction) - if self._items.GetSelection() == -1: - self._items.SetSelection(self._items.GetItemCount()-1) - elif self._items.GetSelection() == self._items.GetItemCount(): - self._items.SetSelection(0) - if self._items.GetSelection() == oldSel: - break - - else: - break - - self.SetTransparency() - selection = self._items.GetItem(self._items.GetSelection()).GetWindow() - pane = self._aui_manager.GetPane(selection) - - if not pane.IsOk(): - if isinstance(selection.GetParent(), auibook.AuiNotebook): - self.SetTransparency(selection) - self._aui_manager.ShowHint(selection.GetScreenRect()) - wx.CallAfter(self.SetFocus) - self.SetFocus() - return - else: - self._aui_manager.HideHint() - return - if not pane.IsShown(): - self._aui_manager.HideHint() - return - - self.SetTransparency(selection) - self._aui_manager.ShowHint(selection.GetScreenRect()) - # NOTE: this is odd but it is the only way for the focus to - # work correctly on wxMac... - wx.CallAfter(self.SetFocus) - self.SetFocus() - - - def SetTransparency(self, selection=None): - - if not self.GetParent().CanSetTransparent(): - return - - if selection is not None: - intersects = False - if selection.GetScreenRect().Intersects(self.GetParent().GetScreenRect()): - intersects = True - self.GetParent().SetTransparent(200) - return - - self.GetParent().SetTransparent(255) - - - def GenerateSelectionEvent(self): - - event = wx.CommandEvent(wx.wxEVT_COMMAND_LISTBOX_SELECTED, self.GetId()) - event.SetEventObject(self) - event.SetInt(self._items.GetSelection()) - self.GetEventHandler().ProcessEvent(event) - - - def CalculateLayout(self, dc=None): - - if dc is None: - dc = wx.ClientDC(self) - - if self._items.GetSelection() == -1: - self._items.SetSelection(0) - - columnCount = 1 - - # Spacing between edge of window or between columns - xMargin = 4 - yMargin = 4 - - # Inter-row spacing - rowSpacing = 2 - - itemSize = self._items.CalculateItemSize(dc) - self._overallSize = wx.Size(350, 200) - - currentRow = 0 - x = xMargin - y = yMargin - - breaking = False - i = 0 - - while 1: - - oldOverallSize = self._overallSize - item = self._items.GetItem(i) - - item.SetRect(wx.Rect(x, y, itemSize.x, itemSize.y)) - item.SetColPos(columnCount-1) - item.SetRowPos(currentRow) - - if item.GetRect().GetBottom() > self._overallSize.y: - self._overallSize.y = item.GetRect().GetBottom() + yMargin - - if item.GetRect().GetRight() > self._overallSize.x: - self._overallSize.x = item.GetRect().GetRight() + xMargin - - currentRow += 1 - - y += rowSpacing + itemSize.y - stopBreaking = breaking - - if currentRow > self._items.GetRowCount() or (item.GetBreakColumn() and not breaking and currentRow != 1): - currentRow = 0 - columnCount += 1 - x += xMargin + itemSize.x - y = yMargin - - # Make sure we don't orphan a group - if item.GetIsGroup() or (item.GetBreakColumn() and not breaking): - self._overallSize = oldOverallSize - - if item.GetBreakColumn(): - breaking = True - - # Repeat the last item, in the next column - i -= 1 - - if stopBreaking: - breaking = False - - i += 1 - - if i >= self._items.GetItemCount(): - break - - self._items.SetColumnCount(columnCount) - self.InvalidateBestSize() - - - def SetItems(self, items): - - self._items = items - - - def GetItems(self): - - return self._items - - - def SetExtraNavigationKey(self, keyCode): - """ - Set an extra key that can be used to cycle through items, - in case not using the ``Ctrl`` + ``Tab`` combination. - """ - - self._extraNavigationKey = keyCode - - - def GetExtraNavigationKey(self): - - return self._extraNavigationKey - - - def SetModifierKey(self, modifierKey): - """ - Set the modifier used to invoke the dialog, and therefore to test for release. - """ - - self._modifierKey = modifierKey - - - def GetModifierKey(self): - - return self._modifierKey - - - -class SwitcherDialog(wx.Dialog): - """ - SwitcherDialog shows a :class:`Dialog` with a list of panes and tabs for the user to choose. - ``Ctrl`` + ``Tab`` cycles through them. - """ - - def __init__(self, items, parent, aui_manager, id=wx.ID_ANY, title=_("Pane Switcher"), pos=wx.DefaultPosition, - size=wx.DefaultSize, style=wx.STAY_ON_TOP|wx.DIALOG_NO_PARENT|wx.BORDER_SIMPLE): - """ Default class constructor. """ - - self._switcherBorderStyle = (style & wx.BORDER_MASK) - if self._switcherBorderStyle == wx.BORDER_NONE: - self._switcherBorderStyle = wx.BORDER_SIMPLE - - style &= wx.BORDER_MASK - style |= wx.BORDER_NONE - - wx.Dialog.__init__(self, parent, id, title, pos, size, style) - - self._listCtrl = MultiColumnListCtrl(self, aui_manager, - style=wx.WANTS_CHARS|wx.NO_BORDER) - self._listCtrl.SetItems(items) - self._listCtrl.CalculateLayout() - - self._descriptionCtrl = wx.html.HtmlWindow(self, size=(-1, 100), style=wx.BORDER_NONE) - self._descriptionCtrl.SetBackgroundColour(self.GetBackgroundColour()) - - if wx.Platform == "__WXGTK__": - fontSize = 11 - self._descriptionCtrl.SetStandardFonts(fontSize) - - sizer = wx.BoxSizer(wx.VERTICAL) - self.SetSizer(sizer) - sizer.Add(self._listCtrl, 1, wx.ALL|wx.EXPAND, 10) - sizer.Add(self._descriptionCtrl, 0, wx.ALL|wx.EXPAND, 10) - sizer.SetSizeHints(self) - - self._listCtrl.SetFocus() - - self.Centre(wx.BOTH) - - if self._listCtrl.GetItems().GetSelection() == -1: - self._listCtrl.GetItems().SetSelection(0) - - self._listCtrl.AdvanceToNextSelectableItem(1) - - self.ShowDescription(self._listCtrl.GetItems().GetSelection()) - - self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) - self.Bind(wx.EVT_ACTIVATE, self.OnActivate) - self.Bind(wx.EVT_LISTBOX, self.OnSelectItem) - self.Bind(wx.EVT_PAINT, self.OnPaint) - - # Attributes - self._closing = False - if wx.Platform == "__WXMSW__": - self._borderColour = wx.Colour(49, 106, 197) - else: - self._borderColour = wx.BLACK - - self._aui_manager = aui_manager - - - def OnCloseWindow(self, event): - - if self._closing: - return - - if self.IsModal(): - self._closing = True - - if self.GetSelection() == -1: - self.EndModal(wx.ID_CANCEL) - else: - self.EndModal(wx.ID_OK) - - self._aui_manager.HideHint() - - - def GetSelection(self): - - return self._listCtrl.GetItems().GetSelection() - - - def OnActivate(self, event): - - if not event.GetActive(): - if not self._closing: - self._closing = True - self.EndModal(wx.ID_CANCEL) - - - def OnPaint(self, event): - - dc = wx.PaintDC(self) - - if self._switcherBorderStyle == wx.BORDER_SIMPLE: - - dc.SetPen(wx.Pen(self._borderColour)) - dc.SetBrush(wx.TRANSPARENT_BRUSH) - - rect = self.GetClientRect() - dc.DrawRectangleRect(rect) - - # Draw border around the HTML control - rect = wx.Rect(*self._descriptionCtrl.GetRect()) - rect.Inflate(1, 1) - dc.DrawRectangleRect(rect) - - - def OnSelectItem(self, event): - - self.ShowDescription(event.GetSelection()) - - - # Convert a colour to a 6-digit hex string - def ColourToHexString(self, col): - - hx = '%02x%02x%02x' % tuple([int(c) for c in col]) - return hx - - - def ShowDescription(self, i): - - item = self._listCtrl.GetItems().GetItem(i) - colour = self._listCtrl.GetItems().GetBackgroundColour() - - if not colour.IsOk(): - colour = self.GetBackgroundColour() - - backgroundColourHex = self.ColourToHexString(colour) - html = _("") + item.GetTitle() + _("") - - if item.GetDescription(): - html += _("

") - html += item.GetDescription() - - html += _("") - self._descriptionCtrl.SetPage(html) - - - def SetExtraNavigationKey(self, keyCode): - - self._extraNavigationKey = keyCode - if self._listCtrl: - self._listCtrl.SetExtraNavigationKey(keyCode) - - - def GetExtraNavigationKey(self): - - return self._extraNavigationKey - - - def SetModifierKey(self, modifierKey): - - self._modifierKey = modifierKey - if self._listCtrl: - self._listCtrl.SetModifierKey(modifierKey) - - - def GetModifierKey(self): - - return self._modifierKey - - - def SetBorderColour(self, colour): - - self._borderColour = colour - - \ No newline at end of file diff --git a/enaml/wx/wx_upstream/aui/aui_utilities.py b/enaml/wx/wx_upstream/aui/aui_utilities.py deleted file mode 100644 index ae55fcc84..000000000 --- a/enaml/wx/wx_upstream/aui/aui_utilities.py +++ /dev/null @@ -1,677 +0,0 @@ -""" -This module contains some common functions used by :mod:`lib.agw.aui` to -manipulate colours, bitmaps, text, gradient shadings and custom dragging images -for :class:`~lib.agw.aui.auibook.AuiNotebook` tabs. -""" - -__author__ = "Andrea Gavana " -__date__ = "31 March 2009" - - -import wx - -from aui_constants import * - - -if wx.Platform == "__WXMAC__": - import Carbon.Appearance - - -def BlendColour(fg, bg, alpha): - """ - Blends the two colour component `fg` and `bg` into one colour component, adding - an optional alpha channel. - - :param Colour `fg`: the first colour component; - :param Colour `bg`: the second colour component; - :param integer `alpha`: an optional transparency value. - """ - - result = bg + (alpha*(fg - bg)) - - if result < 0.0: - result = 0.0 - if result > 255: - result = 255 - - return result - - -def StepColour(c, ialpha): - """ - Darken/lighten the input colour `c`. - - :param Colour `c`: a colour to darken/lighten; - :param integer `ialpha`: a transparency value. - """ - - if ialpha == 100: - return c - - r, g, b = c.Red(), c.Green(), c.Blue() - - # ialpha is 0..200 where 0 is completely black - # and 200 is completely white and 100 is the same - # convert that to normal alpha 0.0 - 1.0 - ialpha = min(ialpha, 200) - ialpha = max(ialpha, 0) - alpha = (ialpha - 100.0)/100.0 - - if ialpha > 100: - - # blend with white - bg = 255 - alpha = 1.0 - alpha # 0 = transparent fg 1 = opaque fg - - else: - - # blend with black - bg = 0 - alpha = 1.0 + alpha # 0 = transparent fg 1 = opaque fg - - r = BlendColour(r, bg, alpha) - g = BlendColour(g, bg, alpha) - b = BlendColour(b, bg, alpha) - - return wx.Colour(r, g, b) - - -def LightContrastColour(c): - """ - Creates a new, lighter colour based on the input colour `c`. - - :param Colour `c`: the input colour to analyze. - """ - - amount = 120 - - # if the colour is especially dark, then - # make the contrast even lighter - if c.Red() < 128 and c.Green() < 128 and c.Blue() < 128: - amount = 160 - - return StepColour(c, amount) - - -def ChopText(dc, text, max_size): - """ - Chops the input `text` if its size does not fit in `max_size`, by cutting the - text and adding ellipsis at the end. - - :param `dc`: a :class:`DC` device context; - :param string `text`: the text to chop; - :param integer `max_size`: the maximum size in which the text should fit. - """ - - # first check if the text fits with no problems - x, y, dummy = dc.GetMultiLineTextExtent(text) - - if x <= max_size: - return text - - textLen = len(text) - last_good_length = 0 - - for i in xrange(textLen, -1, -1): - s = text[0:i] - s += "..." - - x, y = dc.GetTextExtent(s) - last_good_length = i - - if x < max_size: - break - - ret = text[0:last_good_length] + "..." - return ret - - -def BitmapFromBits(bits, w, h, colour): - """ - A utility function that creates a masked bitmap from raw bits (XBM format). - - :param string `bits`: the raw bits of the bitmap; - :param integer `w`: the bitmap width; - :param integer `h`: the bitmap height; - :param Colour `colour`: the colour which will replace all white pixels in the - raw bitmap. - """ - - img = wx.BitmapFromBits(bits, w, h).ConvertToImage() - img.Replace(0, 0, 0, 123, 123, 123) - img.Replace(255, 255, 255, colour.Red(), colour.Green(), colour.Blue()) - img.SetMaskColour(123, 123, 123) - return wx.BitmapFromImage(img) - - -def IndentPressedBitmap(rect, button_state): - """ - Indents the input rectangle `rect` based on the value of `button_state`. - - :param Rect `rect`: the button bitmap rectangle; - :param integer `button_state`: the button state. - """ - - if button_state == AUI_BUTTON_STATE_PRESSED: - rect.x += 1 - rect.y += 1 - - return rect - - -def GetBaseColour(): - """ - Returns the face shading colour on push buttons/backgrounds, - mimicking as closely as possible the platform UI colours. - """ - - if wx.Platform == "__WXMAC__": - - if hasattr(wx, 'MacThemeColour'): - base_colour = wx.MacThemeColour(Carbon.Appearance.kThemeBrushToolbarBackground) - else: - brush = wx.Brush(wx.BLACK) - brush.MacSetTheme(Carbon.Appearance.kThemeBrushToolbarBackground) - base_colour = brush.GetColour() - - else: - - base_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE) - - # the base_colour is too pale to use as our base colour, - # so darken it a bit - if ((255-base_colour.Red()) + - (255-base_colour.Green()) + - (255-base_colour.Blue()) < 60): - - base_colour = StepColour(base_colour, 92) - - return base_colour - - -def MakeDisabledBitmap(bitmap): - """ - Convert the given image (in place) to a grayed-out version, appropriate for a 'disabled' appearance. - - :param Bitmap `bitmap`: the bitmap to gray-out. - """ - - anImage = bitmap.ConvertToImage() - factor = 0.7 # 0 < f < 1. Higher Is Grayer - - if anImage.HasMask(): - maskColour = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue()) - else: - maskColour = None - - data = map(ord, list(anImage.GetData())) - - for i in range(0, len(data), 3): - - pixel = (data[i], data[i+1], data[i+2]) - pixel = MakeGray(pixel, factor, maskColour) - - for x in range(3): - data[i+x] = pixel[x] - - anImage.SetData(''.join(map(chr, data))) - - return anImage.ConvertToBitmap() - - -def MakeGray(rgbTuple, factor, maskColour): - """ - Make a pixel grayed-out. - - If the pixel matches the `maskColour`, it won't be changed. - - :param tuple `rgbTuple`: a tuple representing a pixel colour; - :param integer `factor`: a graying-out factor; - :param Colour `maskColour`: a colour mask. - """ - - if rgbTuple != maskColour: - r, g, b = rgbTuple - return map(lambda x: int((230 - x) * factor) + x, (r, g, b)) - else: - return rgbTuple - - -def Clip(a, b, c): - """ - Clips the value in `a` based on the extremes `b` and `c`. - - :param `a`: the value to analyze; - :param `b`: a minimum value; - :param `c`: a maximum value. - """ - - return ((a < b and [b]) or [(a > c and [c] or [a])[0]])[0] - - -def LightColour(colour, percent): - """ - Brighten input `colour` by `percent`. - - :param Colour `colour`: the colour to be brightened; - :param integer `percent`: brightening percentage. - """ - - end_colour = wx.WHITE - - rd = end_colour.Red() - colour.Red() - gd = end_colour.Green() - colour.Green() - bd = end_colour.Blue() - colour.Blue() - - high = 100 - - # We take the percent way of the colour from colour -. white - i = percent - r = colour.Red() + ((i*rd*100)/high)/100 - g = colour.Green() + ((i*gd*100)/high)/100 - b = colour.Blue() + ((i*bd*100)/high)/100 - return wx.Colour(r, g, b) - - -def PaneCreateStippleBitmap(): - """ - Creates a stipple bitmap to be used in a :class:`Brush`. - - This is used to draw sash resize hints. - """ - - data = [0, 0, 0, 192, 192, 192, 192, 192, 192, 0, 0, 0] - img = wx.EmptyImage(2, 2) - counter = 0 - - for ii in xrange(2): - for jj in xrange(2): - img.SetRGB(ii, jj, data[counter], data[counter+1], data[counter+2]) - counter = counter + 3 - - return img.ConvertToBitmap() - - -def DrawMACCloseButton(colour, backColour=None): - """ - Draws the wxMAC tab close button using :class:`GraphicsContext`. - - :param Colour `colour`: the colour to use to draw the circle; - :param Colour `backColour`: the optional background colour for the circle. - """ - - bmp = wx.EmptyBitmapRGBA(16, 16) - dc = wx.MemoryDC() - dc.SelectObject(bmp) - - gc = wx.GraphicsContext.Create(dc) - gc.SetBrush(wx.Brush(colour)) - path = gc.CreatePath() - path.AddCircle(6.5, 7, 6.5) - path.CloseSubpath() - gc.FillPath(path) - - path = gc.CreatePath() - if backColour is not None: - pen = wx.Pen(backColour, 2) - else: - pen = wx.Pen("white", 2) - - pen.SetCap(wx.CAP_BUTT) - pen.SetJoin(wx.JOIN_BEVEL) - gc.SetPen(pen) - path.MoveToPoint(3.5, 4) - path.AddLineToPoint(9.5, 10) - path.MoveToPoint(3.5, 10) - path.AddLineToPoint(9.5, 4) - path.CloseSubpath() - gc.DrawPath(path) - - dc.SelectObject(wx.NullBitmap) - return bmp - - -def DarkenBitmap(bmp, caption_colour, new_colour): - """ - Darkens the input bitmap on wxMAC using the input colour. - - :param Bitmap `bmp`: the bitmap to be manipulated; - :param Colour `caption_colour`: the colour of the pane caption; - :param Colour `new_colour`: the colour used to darken the bitmap. - """ - - image = bmp.ConvertToImage() - red = caption_colour.Red()/float(new_colour.Red()) - green = caption_colour.Green()/float(new_colour.Green()) - blue = caption_colour.Blue()/float(new_colour.Blue()) - image = image.AdjustChannels(red, green, blue) - return image.ConvertToBitmap() - - -def DrawGradientRectangle(dc, rect, start_colour, end_colour, direction, offset=0, length=0): - """ - Draws a gradient-shaded rectangle. - - :param `dc`: a :class:`DC` device context; - :param Rect `rect`: the rectangle in which to draw the gradient; - :param Colour `start_colour`: the first colour of the gradient; - :param Colour `end_colour`: the second colour of the gradient; - :param integer `direction`: the gradient direction (horizontal or vertical). - """ - - if direction == AUI_GRADIENT_VERTICAL: - dc.GradientFillLinear(rect, start_colour, end_colour, wx.SOUTH) - else: - dc.GradientFillLinear(rect, start_colour, end_colour, wx.EAST) - - -def FindFocusDescendant(ancestor): - """ - Find a window with the focus, that is also a descendant of the given window. - This is used to determine the window to initially send commands to. - - :param Window `ancestor`: the window to check for ancestry. - """ - - # Process events starting with the window with the focus, if any. - focusWin = wx.Window.FindFocus() - win = focusWin - - # Check if this is a descendant of this frame. - # If not, win will be set to NULL. - while win: - if win == ancestor: - break - else: - win = win.GetParent() - - if win is None: - focusWin = None - - return focusWin - - -def GetLabelSize(dc, label, vertical): - """ - Returns the :class:`~lib.agw.aui.auibar.AuiToolBar` item label size. - - :param string `label`: the toolbar tool label; - :param bool `vertical`: whether the toolbar tool orientation is vertical or not. - """ - - text_width = text_height = 0 - - # get the text height - dummy, text_height = dc.GetTextExtent("ABCDHgj") - # get the text width - if label.strip(): - text_width, dummy = dc.GetTextExtent(label) - - if vertical: - tmp = text_height - text_height = text_width - text_width = tmp - - return wx.Size(text_width, text_height) - - -#--------------------------------------------------------------------------- -# TabDragImage implementation -# This class handles the creation of a custom image when dragging -# AuiNotebook tabs -#--------------------------------------------------------------------------- - -class TabDragImage(wx.DragImage): - """ - This class handles the creation of a custom image in case of drag and drop of a notebook tab. - """ - - def __init__(self, notebook, page, button_state, tabArt): - """ - Default class constructor. - - For internal use: do not call it in your code! - - :param `notebook`: an instance of :class:`~lib.agw.aui.auibook.AuiNotebook`; - :param `page`: the dragged :class:`~lib.agw.aui.auibook.AuiNotebookPage` page; - :param integer `button_state`: the state of the close button on the tab; - :param `tabArt`: an instance of :class:`~lib.agw.aui.tabart.AuiDefaultTabArt` or one of its derivations. - """ - - self._backgroundColour = wx.NamedColour("pink") - self._bitmap = self.CreateBitmap(notebook, page, button_state, tabArt) - wx.DragImage.__init__(self, self._bitmap) - - - def CreateBitmap(self, notebook, page, button_state, tabArt): - """ - Actually creates the drag and drop bitmap. - - :param `notebook`: an instance of :class:`~lib.agw.aui.auibook.AuiNotebook`; - :param `page`: the dragged :class:`~lib.agw.aui.auibook.AuiNotebookPage` page; - :param integer `button_state`: the state of the close button on the tab; - :param `tabArt`: an instance of :class:`~lib.agw.aui.tabart.AuiDefaultTabArt` or one of its derivations. - """ - - control = page.control - memory = wx.MemoryDC(wx.EmptyBitmap(1, 1)) - - tab_size, x_extent = tabArt.GetTabSize(memory, notebook, page.caption, page.bitmap, page.active, - button_state, control) - - tab_width, tab_height = tab_size - rect = wx.Rect(0, 0, tab_width, tab_height) - - bitmap = wx.EmptyBitmap(tab_width+1, tab_height+1) - memory.SelectObject(bitmap) - - if wx.Platform == "__WXMAC__": - memory.SetBackground(wx.TRANSPARENT_BRUSH) - else: - memory.SetBackground(wx.Brush(self._backgroundColour)) - - memory.SetBackgroundMode(wx.TRANSPARENT) - memory.Clear() - - paint_control = wx.Platform != "__WXMAC__" - tabArt.DrawTab(memory, notebook, page, rect, button_state, paint_control=paint_control) - - memory.SetBrush(wx.TRANSPARENT_BRUSH) - memory.SetPen(wx.BLACK_PEN) - memory.DrawRoundedRectangle(0, 0, tab_width+1, tab_height+1, 2) - - memory.SelectObject(wx.NullBitmap) - - # Gtk and Windows unfortunatly don't do so well with transparent - # drawing so this hack corrects the image to have a transparent - # background. - if wx.Platform != '__WXMAC__': - timg = bitmap.ConvertToImage() - if not timg.HasAlpha(): - timg.InitAlpha() - for y in xrange(timg.GetHeight()): - for x in xrange(timg.GetWidth()): - pix = wx.Colour(timg.GetRed(x, y), - timg.GetGreen(x, y), - timg.GetBlue(x, y)) - if pix == self._backgroundColour: - timg.SetAlpha(x, y, 0) - bitmap = timg.ConvertToBitmap() - return bitmap - - -def GetDockingImage(direction, useAero, center): - """ - Returns the correct name of the docking bitmap depending on the input parameters. - - :param bool `useAero`: whether :class:`~lib.agw.aui.framemanager.AuiManager` is using - Aero-style or Whidbey-style docking images or not; - :param bool `center`: whether we are looking for the center diamond-shaped bitmap or not. - """ - - suffix = (center and [""] or ["_single"])[0] - prefix = "" - if useAero == 2: - # Whidbey docking guides - prefix = "whidbey_" - elif useAero == 1: - # Aero docking style - prefix = "aero_" - - if direction == wx.TOP: - bmp_unfocus = eval("%sup%s"%(prefix, suffix)).GetBitmap() - bmp_focus = eval("%sup_focus%s"%(prefix, suffix)).GetBitmap() - elif direction == wx.BOTTOM: - bmp_unfocus = eval("%sdown%s"%(prefix, suffix)).GetBitmap() - bmp_focus = eval("%sdown_focus%s"%(prefix, suffix)).GetBitmap() - elif direction == wx.LEFT: - bmp_unfocus = eval("%sleft%s"%(prefix, suffix)).GetBitmap() - bmp_focus = eval("%sleft_focus%s"%(prefix, suffix)).GetBitmap() - elif direction == wx.RIGHT: - bmp_unfocus = eval("%sright%s"%(prefix, suffix)).GetBitmap() - bmp_focus = eval("%sright_focus%s"%(prefix, suffix)).GetBitmap() - else: - bmp_unfocus = eval("%stab%s"%(prefix, suffix)).GetBitmap() - bmp_focus = eval("%stab_focus%s"%(prefix, suffix)).GetBitmap() - - return bmp_unfocus, bmp_focus - - -def TakeScreenShot(rect): - """ - Takes a screenshot of the screen at given position and size (`rect`). - - :param Rect `rect`: the screen rectangle for which we want to take a screenshot. - """ - - # Create a DC for the whole screen area - dcScreen = wx.ScreenDC() - - # Create a Bitmap that will later on hold the screenshot image - # Note that the Bitmap must have a size big enough to hold the screenshot - # -1 means using the current default colour depth - bmp = wx.EmptyBitmap(rect.width, rect.height) - - # Create a memory DC that will be used for actually taking the screenshot - memDC = wx.MemoryDC() - - # Tell the memory DC to use our Bitmap - # all drawing action on the memory DC will go to the Bitmap now - memDC.SelectObject(bmp) - - # Blit (in this case copy) the actual screen on the memory DC - # and thus the Bitmap - memDC.Blit( 0, # Copy to this X coordinate - 0, # Copy to this Y coordinate - rect.width, # Copy this width - rect.height, # Copy this height - dcScreen, # From where do we copy? - rect.x, # What's the X offset in the original DC? - rect.y # What's the Y offset in the original DC? - ) - - # Select the Bitmap out of the memory DC by selecting a new - # uninitialized Bitmap - memDC.SelectObject(wx.NullBitmap) - - return bmp - - -def RescaleScreenShot(bmp, thumbnail_size=200): - """ - Rescales a bitmap to be `thumbnail_size` pixels wide (or tall) at maximum. - - :param Bitmap `bmp`: the bitmap to rescale; - :param integer `thumbnail_size`: the maximum size of every page thumbnail. - """ - - bmpW, bmpH = bmp.GetWidth(), bmp.GetHeight() - img = bmp.ConvertToImage() - - newW, newH = bmpW, bmpH - - if bmpW > bmpH: - if bmpW > thumbnail_size: - ratio = bmpW/float(thumbnail_size) - newW, newH = int(bmpW/ratio), int(bmpH/ratio) - img.Rescale(newW, newH, wx.IMAGE_QUALITY_HIGH) - else: - if bmpH > thumbnail_size: - ratio = bmpH/float(thumbnail_size) - newW, newH = int(bmpW/ratio), int(bmpH/ratio) - img.Rescale(newW, newH, wx.IMAGE_QUALITY_HIGH) - - newBmp = img.ConvertToBitmap() - otherBmp = wx.EmptyBitmap(newW+5, newH+5) - - memDC = wx.MemoryDC() - memDC.SelectObject(otherBmp) - memDC.SetBackground(wx.WHITE_BRUSH) - memDC.Clear() - - memDC.SetPen(wx.TRANSPARENT_PEN) - - pos = 0 - for i in xrange(5, 0, -1): - brush = wx.Brush(wx.Colour(50*i, 50*i, 50*i)) - memDC.SetBrush(brush) - memDC.DrawRoundedRectangle(0, 0, newW+5-pos, newH+5-pos, 2) - pos += 1 - - memDC.DrawBitmap(newBmp, 0, 0, True) - - # Select the Bitmap out of the memory DC by selecting a new - # uninitialized Bitmap - memDC.SelectObject(wx.NullBitmap) - - return otherBmp - - -def GetSlidingPoints(rect, size, direction): - """ - Returns the point at which the sliding in and out of a minimized pane begins. - - :param Rect `rect`: the :class:`~lib.agw.aui.auibar.AuiToolBar` tool screen rectangle; - :param Size `size`: the pane window size; - :param integer `direction`: the pane docking direction. - """ - - if direction == AUI_DOCK_LEFT: - startX, startY = rect.x + rect.width + 2, rect.y - elif direction == AUI_DOCK_TOP: - startX, startY = rect.x, rect.y + rect.height + 2 - elif direction == AUI_DOCK_RIGHT: - startX, startY = rect.x - size.x - 2, rect.y - elif direction == AUI_DOCK_BOTTOM: - startX, startY = rect.x, rect.y - size.y - 2 - else: - raise Exception("How did we get here?") - - caption_height = wx.SystemSettings.GetMetric(wx.SYS_CAPTION_Y) - frame_border_x = wx.SystemSettings.GetMetric(wx.SYS_FRAMESIZE_X) - frame_border_y = wx.SystemSettings.GetMetric(wx.SYS_FRAMESIZE_Y) - - stopX = size.x + caption_height + frame_border_x - stopY = size.x + frame_border_y - - return startX, startY, stopX, stopY - - -def CopyAttributes(newArt, oldArt): - """ - Copies pens, brushes, colours and fonts from the old tab art to the new one. - - :param `newArt`: the new instance of :class:`~lib.agw.aui.tabart.AuiDefaultTabArt`; - :param `oldArt`: the old instance of :class:`~lib.agw.aui.tabart.AuiDefaultTabArt`. - """ - - attrs = dir(oldArt) - - for attr in attrs: - if attr.startswith("_") and (attr.endswith("_colour") or attr.endswith("_font") or \ - attr.endswith("_font") or attr.endswith("_brush") or \ - attr.endswith("Pen") or attr.endswith("_pen")): - setattr(newArt, attr, getattr(oldArt, attr)) - - return newArt - diff --git a/enaml/wx/wx_upstream/aui/auibar.py b/enaml/wx/wx_upstream/aui/auibar.py deleted file mode 100644 index 32bcd7db5..000000000 --- a/enaml/wx/wx_upstream/aui/auibar.py +++ /dev/null @@ -1,3960 +0,0 @@ -""" -`auibar.py` contains an implementation of :class:`AuiToolBar`, which is a completely owner-drawn -toolbar perfectly integrated with the AUI layout system. This allows drag and drop of -toolbars, docking/floating behaviour and the possibility to define "overflow" items -in the toolbar itself. - -The default theme that is used is :class:`AuiToolBar`, which provides a modern, -glossy look and feel. The theme can be changed by calling :meth:`AuiToolBar.SetArtProvider`. -""" - -__author__ = "Andrea Gavana " -__date__ = "31 March 2009" - - -import wx -import types - -from aui_utilities import BitmapFromBits, StepColour, GetLabelSize -from aui_utilities import GetBaseColour, MakeDisabledBitmap - -import framemanager -from aui_constants import * - -# wxPython version string -_VERSION_STRING = wx.VERSION_STRING - -# AuiToolBar events -wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN = wx.NewEventType() -wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK = wx.NewEventType() -wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK = wx.NewEventType() -wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK = wx.NewEventType() -wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG = wx.NewEventType() - -EVT_AUITOOLBAR_TOOL_DROPDOWN = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, 1) -""" A dropdown `AuiToolBarItem` is being shown. """ -EVT_AUITOOLBAR_OVERFLOW_CLICK = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, 1) -""" The user left-clicked on the overflow button in `AuiToolBar`. """ -EVT_AUITOOLBAR_RIGHT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, 1) -""" Fires an event when the user right-clicks on a `AuiToolBarItem`. """ -EVT_AUITOOLBAR_MIDDLE_CLICK = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, 1) -""" Fires an event when the user middle-clicks on a `AuiToolBarItem`. """ -EVT_AUITOOLBAR_BEGIN_DRAG = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, 1) -""" A drag operation involving a toolbar item has started. """ - -# ---------------------------------------------------------------------- - -class CommandToolBarEvent(wx.PyCommandEvent): - """ A specialized command event class for events sent by :class:`AuiToolBar`. """ - - def __init__(self, command_type, win_id): - """ - Default class constructor. - - :param `command_type`: the event kind or an instance of :class:`PyCommandEvent`. - :param integer `win_id`: the window identification number. - """ - - if type(command_type) == types.IntType: - wx.PyCommandEvent.__init__(self, command_type, win_id) - else: - wx.PyCommandEvent.__init__(self, command_type.GetEventType(), command_type.GetId()) - - self.is_dropdown_clicked = False - self.click_pt = wx.Point(-1, -1) - self.rect = wx.Rect(-1, -1, 0, 0) - self.tool_id = -1 - - - def IsDropDownClicked(self): - """ Returns whether the drop down menu has been clicked. """ - - return self.is_dropdown_clicked - - - def SetDropDownClicked(self, c): - """ - Sets whether the drop down menu has been clicked. - - :param bool `c`: ``True`` to set the drop down as clicked, ``False`` otherwise. - """ - - self.is_dropdown_clicked = c - - - def GetClickPoint(self): - """ Returns the point where the user clicked with the mouse. """ - - return self.click_pt - - - def SetClickPoint(self, p): - """ - Sets the clicking point. - - :param Point `p`: the location of the mouse click. - """ - - self.click_pt = p - - - def GetItemRect(self): - """ Returns the :class:`AuiToolBarItem` rectangle. """ - - return self.rect - - - def SetItemRect(self, r): - """ - Sets the :class:`AuiToolBarItem` rectangle. - - :param Rect `r`: the toolbar item rectangle. - """ - - self.rect = r - - - def GetToolId(self): - """ Returns the :class:`AuiToolBarItem` identifier. """ - - return self.tool_id - - - def SetToolId(self, id): - """ - Sets the :class:`AuiToolBarItem` identifier. - - :param integer `id`: the toolbar item identifier. - """ - - self.tool_id = id - - -# ---------------------------------------------------------------------- - -class AuiToolBarEvent(CommandToolBarEvent): - """ A specialized command event class for events sent by :class:`AuiToolBar`. """ - - def __init__(self, command_type=None, win_id=0): - """ - Default class constructor. - - :param `command_type`: the event kind or an instance of :class:`PyCommandEvent`. - :param integer `win_id`: the window identification number. - """ - - CommandToolBarEvent.__init__(self, command_type, win_id) - - if type(command_type) == types.IntType: - self.notify = wx.NotifyEvent(command_type, win_id) - else: - self.notify = wx.NotifyEvent(command_type.GetEventType(), command_type.GetId()) - - - def GetNotifyEvent(self): - """ Returns the actual :class:`NotifyEvent`. """ - - return self.notify - - - def IsAllowed(self): - """ Returns whether the event is allowed or not. """ - - return self.notify.IsAllowed() - - - def Veto(self): - """ - Prevents the change announced by this event from happening. - - It is in general a good idea to notify the user about the reasons for - vetoing the change because otherwise the applications behaviour (which - just refuses to do what the user wants) might be quite surprising. - """ - - self.notify.Veto() - - - def Allow(self): - """ - This is the opposite of :meth:`Veto`: it explicitly allows the event to be - processed. For most events it is not necessary to call this method as the - events are allowed anyhow but some are forbidden by default (this will - be mentioned in the corresponding event description). - """ - - self.notify.Allow() - - -# ---------------------------------------------------------------------- - -class ToolbarCommandCapture(wx.PyEvtHandler): - """ A class to handle the dropdown window menu. """ - - def __init__(self): - """ Default class constructor. """ - - wx.PyEvtHandler.__init__(self) - self._last_id = 0 - - - def GetCommandId(self): - """ Returns the event command identifier. """ - - return self._last_id - - - def ProcessEvent(self, event): - """ - Processes an event, searching event tables and calling zero or more suitable - event handler function(s). - - :param `event`: the event to process. - - :note: Normally, your application would not call this function: it is called - in the wxPython implementation to dispatch incoming user interface events - to the framework (and application). - However, you might need to call it if implementing new functionality (such as - a new control) where you define new event types, as opposed to allowing the - user to override functions. - - An instance where you might actually override the :meth:`ProcessEvent` function is where - you want to direct event processing to event handlers not normally noticed by - wxPython. For example, in the document/view architecture, documents and views - are potential event handlers. When an event reaches a frame, :meth:`ProcessEvent` will - need to be called on the associated document and view in case event handler - functions are associated with these objects. - - The normal order of event table searching is as follows: - - 1. If the object is disabled (via a call to :meth:`~EvtHandler.SetEvtHandlerEnabled`) the function - skips to step (6). - 2. If the object is a :class:`Window`, :meth:`ProcessEvent` is recursively called on the window's - :class:`Validator`. If this returns ``True``, the function exits. - 3. wxWidgets `SearchEventTable` is called for this event handler. If this fails, the - base class table is tried, and so on until no more tables exist or an appropriate - function was found, in which case the function exits. - 4. The search is applied down the entire chain of event handlers (usually the chain - has a length of one). If this succeeds, the function exits. - 5. If the object is a :class:`Window` and the event is a :class:`CommandEvent`, :meth:`ProcessEvent` is - recursively applied to the parent window's event handler. If this returns ``True``, - the function exits. - 6. Finally, :meth:`ProcessEvent` is called on the :class:`App` object. - """ - - if event.GetEventType() == wx.wxEVT_COMMAND_MENU_SELECTED: - self._last_id = event.GetId() - return True - - if self.GetNextHandler(): - return self.GetNextHandler().ProcessEvent(event) - - return False - - -# ---------------------------------------------------------------------- - -class AuiToolBarItem(object): - """ - AuiToolBarItem is a toolbar element. - - It has a unique id (except for the separators which always have id = -1), the - style (telling whether it is a normal button, separator or a control), the - state (toggled or not, enabled or not) and short and long help strings. The - default implementations use the short help string for the tooltip text which - is popped up when the mouse pointer enters the tool and the long help string - for the applications status bar. - """ - - def __init__(self, item=None): - """ - Default class constructor. - - :param `item`: another instance of :class:`AuiToolBarItem`. - """ - - if item: - self.Assign(item) - return - - self.window = None - self.clockwisebmp = wx.NullBitmap - self.counterclockwisebmp = wx.NullBitmap - self.clockwisedisbmp = wx.NullBitmap - self.counterclockwisedisbmp = wx.NullBitmap - self.sizer_item = None - self.spacer_pixels = 0 - self.id = 0 - self.kind = ITEM_NORMAL - self.state = 0 # normal, enabled - self.proportion = 0 - self.active = True - self.dropdown = True - self.sticky = True - self.user_data = 0 - - self.label = "" - self.bitmap = wx.NullBitmap - self.disabled_bitmap = wx.NullBitmap - self.hover_bitmap = wx.NullBitmap - self.short_help = "" - self.long_help = "" - self.target = None - self.min_size = wx.Size(-1, -1) - self.alignment = wx.ALIGN_CENTER - self.orientation = AUI_TBTOOL_HORIZONTAL - - - def Assign(self, c): - """ - Assigns the properties of the :class:`AuiToolBarItem` `c` to `self`. - - :param `c`: another instance of :class:`AuiToolBarItem`. - """ - - self.window = c.window - self.label = c.label - self.bitmap = c.bitmap - self.disabled_bitmap = c.disabled_bitmap - self.hover_bitmap = c.hover_bitmap - self.short_help = c.short_help - self.long_help = c.long_help - self.sizer_item = c.sizer_item - self.min_size = c.min_size - self.spacer_pixels = c.spacer_pixels - self.id = c.id - self.kind = c.kind - self.state = c.state - self.proportion = c.proportion - self.active = c.active - self.dropdown = c.dropdown - self.sticky = c.sticky - self.user_data = c.user_data - self.alignment = c.alignment - self.orientation = c.orientation - self.target = c.target - - - def SetWindow(self, w): - """ - Assigns a window to the toolbar item. - - :param Window `w`: associate this window `w` to the :class:`AuiToolBarItem`. - """ - - self.window = w - - - def GetWindow(self): - """ Returns window associated to the toolbar item. """ - - return self.window - - - def SetId(self, new_id): - """ - Sets the toolbar item identifier. - - :param integer `new_id`: the new tool id. - """ - - self.id = new_id - - - def GetId(self): - """ Returns the toolbar item identifier. """ - - return self.id - - - def SetKind(self, new_kind): - """ - Sets the :class:`AuiToolBarItem` kind. - - :param integer `new_kind`: can be one of the following items: - - ======================== ============================= - Item Kind Description - ======================== ============================= - ``ITEM_CONTROL`` The item in the :class:`AuiToolBar` is a control - ``ITEM_LABEL`` The item in the :class:`AuiToolBar` is a text label - ``ITEM_SPACER`` The item in the :class:`AuiToolBar` is a spacer - ``ITEM_SEPARATOR`` The item in the :class:`AuiToolBar` is a separator - ``ITEM_CHECK`` The item in the :class:`AuiToolBar` is a toolbar check item - ``ITEM_NORMAL`` The item in the :class:`AuiToolBar` is a standard toolbar item - ``ITEM_RADIO`` The item in the :class:`AuiToolBar` is a toolbar radio item - ======================== ============================= - """ - - self.kind = new_kind - - - def GetKind(self): - """ - Returns the toolbar item kind. - - See :meth:`SetKind` for more details. - """ - - return self.kind - - - def SetState(self, new_state): - """ - Sets the toolbar item state. - - :param `new_state`: can be one of the following states: - - ============================================ ====================================== - Button State Constant Description - ============================================ ====================================== - ``AUI_BUTTON_STATE_NORMAL`` Normal button state - ``AUI_BUTTON_STATE_HOVER`` Hovered button state - ``AUI_BUTTON_STATE_PRESSED`` Pressed button state - ``AUI_BUTTON_STATE_DISABLED`` Disabled button state - ``AUI_BUTTON_STATE_HIDDEN`` Hidden button state - ``AUI_BUTTON_STATE_CHECKED`` Checked button state - ============================================ ====================================== - - """ - - self.state = new_state - - - def GetState(self): - """ - Returns the toolbar item state. - - :see: :meth:`SetState` for more details. - """ - - return self.state - - - def SetSizerItem(self, s): - """ - Associates a sizer item to this toolbar item. - - :param `s`: an instance of :class:`SizerItem`. - """ - - self.sizer_item = s - - - def GetSizerItem(self): - """ Returns the associated sizer item. """ - - return self.sizer_item - - - def SetLabel(self, s): - """ - Sets the toolbar item label. - - :param string `s`: the toolbar item label. - """ - - self.label = s - - - def GetLabel(self): - """ Returns the toolbar item label. """ - - return self.label - - - def SetBitmap(self, bmp): - """ - Sets the toolbar item bitmap. - - :param Bitmap `bmp`: the image associated with this :class:`AuiToolBarItem`. - """ - - self.bitmap = bmp - - - def GetBitmap(self): - """ Returns the toolbar item bitmap. """ - - return self.GetRotatedBitmap(False) - - - def SetDisabledBitmap(self, bmp): - """ - Sets the toolbar item disabled bitmap. - - :param Bitmap `bmp`: the disabled image associated with this :class:`AuiToolBarItem`. - """ - - self.disabled_bitmap = bmp - - - def GetDisabledBitmap(self): - """ Returns the toolbar item disabled bitmap. """ - - return self.GetRotatedBitmap(True) - - - def SetHoverBitmap(self, bmp): - """ - Sets the toolbar item hover bitmap. - - :param Bitmap `bmp`: the hover image associated with this :class:`AuiToolBarItem`. - """ - - self.hover_bitmap = bmp - - - def SetOrientation(self, a): - """ - Sets the toolbar tool orientation. - - :param integer `a`: one of ``AUI_TBTOOL_HORIZONTAL``, ``AUI_TBTOOL_VERT_CLOCKWISE`` or - ``AUI_TBTOOL_VERT_COUNTERCLOCKWISE``. - """ - - self.orientation = a - - - def GetOrientation(self): - """ Returns the toolbar tool orientation. """ - - return self.orientation - - - def GetHoverBitmap(self): - """ Returns the toolbar item hover bitmap. """ - - return self.hover_bitmap - - - def GetRotatedBitmap(self, disabled): - """ - Returns the correct bitmap depending on the tool orientation. - - :param bool `disabled`: whether to return the disabled bitmap or not. - """ - - bitmap_to_rotate = (disabled and [self.disabled_bitmap] or [self.bitmap])[0] - if not bitmap_to_rotate.IsOk() or self.orientation == AUI_TBTOOL_HORIZONTAL: - return bitmap_to_rotate - - rotated_bitmap = wx.NullBitmap - clockwise = True - if self.orientation == AUI_TBTOOL_VERT_CLOCKWISE: - rotated_bitmap = (disabled and [self.clockwisedisbmp] or [self.clockwisebmp])[0] - - elif self.orientation == AUI_TBTOOL_VERT_COUNTERCLOCKWISE: - rotated_bitmap = (disabled and [self.counterclockwisedisbmp] or [self.counterclockwisebmp])[0] - clockwise = False - - if not rotated_bitmap.IsOk(): - rotated_bitmap = wx.BitmapFromImage(bitmap_to_rotate.ConvertToImage().Rotate90(clockwise)) - - return rotated_bitmap - - - def SetShortHelp(self, s): - """ - Sets the short help string for the :class:`AuiToolBarItem`, to be displayed in a - :class:`ToolTip` when the mouse hover over the toolbar item. - - :param string `s`: the tool short help string. - """ - - self.short_help = s - - - def GetShortHelp(self): - """ Returns the short help string for the :class:`AuiToolBarItem`. """ - - return self.short_help - - - def SetLongHelp(self, s): - """ - Sets the long help string for the toolbar item. This string is shown in the - statusbar (if any) of the parent frame when the mouse pointer is inside the - tool. - - :param string `s`: the tool long help string. - """ - - self.long_help = s - - - def GetLongHelp(self): - """ Returns the long help string for the :class:`AuiToolBarItem`. """ - - return self.long_help - - - def SetMinSize(self, s): - """ - Sets the toolbar item minimum size. - - :param Size `s`: the toolbar item minimum size. - """ - - self.min_size = wx.Size(*s) - - - def GetMinSize(self): - """ Returns the toolbar item minimum size. """ - - return self.min_size - - - def SetSpacerPixels(self, s): - """ - Sets the number of pixels for a toolbar item with kind = ``ITEM_SEPARATOR``. - - :param integer `s`: number of pixels. - """ - - self.spacer_pixels = s - - - def GetSpacerPixels(self): - """ Returns the number of pixels for a toolbar item with kind = ``ITEM_SEPARATOR``. """ - - return self.spacer_pixels - - - def SetProportion(self, p): - """ - Sets the :class:`AuiToolBarItem` proportion in the toolbar. - - :param integer `p`: the item proportion. - """ - - self.proportion = p - - - def GetProportion(self): - """ Returns the :class:`AuiToolBarItem` proportion in the toolbar. """ - - return self.proportion - - - def SetActive(self, b): - """ - Activates/deactivates the toolbar item. - - :param bool `b`: ``True`` to activate the item, ``False`` to deactivate it. - """ - - self.active = b - - - def IsActive(self): - """ Returns whether the toolbar item is active or not. """ - - return self.active - - - def SetHasDropDown(self, b): - """ - Sets whether the toolbar item has an associated dropdown menu. - - :param bool `b`: ``True`` to set a dropdown menu, ``False`` otherwise. - """ - - self.dropdown = b - - - def HasDropDown(self): - """ Returns whether the toolbar item has an associated dropdown menu or not. """ - - return self.dropdown - - - def SetSticky(self, b): - """ - Sets whether the toolbar item is sticky (permanent highlight after mouse enter) - or not. - - :param bool `b`: ``True`` to set the item as sticky, ``False`` otherwise. - """ - - self.sticky = b - - - def IsSticky(self): - """ Returns whether the toolbar item has a sticky behaviour or not. """ - - return self.sticky - - - def SetUserData(self, data): - """ - Associates some kind of user data to the toolbar item. - - :param PyObject `data`: a Python object. - - :note: The user data can be any Python object. - """ - - self.user_data = data - - - def GetUserData(self): - """ Returns the associated user data. """ - - return self.user_data - - - def SetAlignment(self, align): - """ - Sets the toolbar item alignment. - - :param integer `align`: the item alignment, which can be one of the available :class:`Sizer` - alignments. - """ - - self.alignment = align - - - def GetAlignment(self): - """ Returns the toolbar item alignment. """ - - return self.alignment - - -# ---------------------------------------------------------------------- - -class AuiDefaultToolBarArt(object): - """ - Toolbar art provider code - a tab provider provides all drawing functionality to the :class:`AuiToolBar`. - This allows the :class:`AuiToolBar` to have a plugable look-and-feel. - - By default, a :class:`AuiToolBar` uses an instance of this class called :class:`AuiDefaultToolBarArt` - which provides bitmap art and a colour scheme that is adapted to the major platforms' - look. You can either derive from that class to alter its behaviour or write a - completely new tab art class. Call :meth:`AuiToolBar.SetArtProvider` to make use this new tab art. - """ - - def __init__(self): - """ Default class constructor. """ - - self.SetDefaultColours() - - self._agwFlags = 0 - self._text_orientation = AUI_TBTOOL_TEXT_BOTTOM - self._highlight_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT) - - self._separator_size = 7 - self._orientation = AUI_TBTOOL_HORIZONTAL - self._gripper_size = 7 - self._overflow_size = 16 - - button_dropdown_bits = "\xe0\xf1\xfb" - overflow_bits = "\x80\xff\x80\xc1\xe3\xf7" - - self._button_dropdown_bmp = BitmapFromBits(button_dropdown_bits, 5, 3, wx.BLACK) - self._disabled_button_dropdown_bmp = BitmapFromBits(button_dropdown_bits, 5, 3, - wx.Colour(128, 128, 128)) - self._overflow_bmp = BitmapFromBits(overflow_bits, 7, 6, wx.BLACK) - self._disabled_overflow_bmp = BitmapFromBits(overflow_bits, 7, 6, wx.Colour(128, 128, 128)) - - self._font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) - - - def SetDefaultColours(self, base_colour=None): - """ - Sets the default colours, which are calculated from the given base colour. - - :param `base_colour`: an instance of :class:`Colour`. If defaulted to ``None``, a colour - is generated accordingly to the platform and theme. - """ - - if base_colour is None: - self._base_colour = GetBaseColour() - else: - self._base_colour = base_colour - - darker3_colour = StepColour(self._base_colour, 60) - darker5_colour = StepColour(self._base_colour, 40) - - self._gripper_pen1 = wx.Pen(darker5_colour) - self._gripper_pen2 = wx.Pen(darker3_colour) - self._gripper_pen3 = wx.WHITE_PEN - - - def Clone(self): - """ Clones the :class:`AuiDefaultToolBarArt` art. """ - - return AuiDefaultToolBarArt() - - - def SetAGWFlags(self, agwFlags): - """ - Sets the toolbar art flags. - - :param integer `agwFlags`: a combination of the following values: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_TB_TEXT`` Shows the text in the toolbar buttons; by default only icons are shown - ``AUI_TB_NO_TOOLTIPS`` Don't show tooltips on :class:`AuiToolBar` items - ``AUI_TB_NO_AUTORESIZE`` Do not auto-resize the :class:`AuiToolBar` - ``AUI_TB_GRIPPER`` Shows a gripper on the :class:`AuiToolBar` - ``AUI_TB_OVERFLOW`` The :class:`AuiToolBar` can contain overflow items - ``AUI_TB_VERTICAL`` The :class:`AuiToolBar` is vertical - ``AUI_TB_HORZ_LAYOUT`` Shows the text and the icons alongside, not vertically stacked. This style - must be used with ``AUI_TB_TEXT`` - ``AUI_TB_PLAIN_BACKGROUND`` Don't draw a gradient background on the toolbar - ``AUI_TB_HORZ_TEXT`` Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT`` - ==================================== ================================== - - """ - - self._agwFlags = agwFlags - - - def GetAGWFlags(self): - """ - Returns the :class:`AuiDefaultToolBarArt` flags. - - :see: :meth:`~AuiDefaultToolBarArt.SetAGWFlags` for more details. - """ - - return self._agwFlags - - - def SetFont(self, font): - """ - Sets the :class:`AuiDefaultToolBarArt` font. - - :param Font `font`: the font used for displaying toolbar item labels. - """ - - self._font = font - - - def SetTextOrientation(self, orientation): - """ - Sets the text orientation. - - :param integer `orientation`: can be one of the following constants: - - ==================================== ================================== - Orientation Switches Description - ==================================== ================================== - ``AUI_TBTOOL_TEXT_LEFT`` Text in :class:`AuiToolBar` items is aligned left - ``AUI_TBTOOL_TEXT_RIGHT`` Text in :class:`AuiToolBar` items is aligned right - ``AUI_TBTOOL_TEXT_TOP`` Text in :class:`AuiToolBar` items is aligned top - ``AUI_TBTOOL_TEXT_BOTTOM`` Text in :class:`AuiToolBar` items is aligned bottom - ==================================== ================================== - - """ - - self._text_orientation = orientation - - - def GetFont(self): - """ Returns the :class:`AuiDefaultToolBarArt` font. """ - - return self._font - - - def GetTextOrientation(self): - """ - Returns the :class:`AuiDefaultToolBarArt` text orientation. - - :see: :meth:`~AuiDefaultToolBarArt.SetTextOrientation` for more details. - """ - - return self._text_orientation - - - def SetOrientation(self, orientation): - """ - Sets the toolbar tool orientation. - - :param integer `orientation`: one of ``AUI_TBTOOL_HORIZONTAL``, ``AUI_TBTOOL_VERT_CLOCKWISE`` or - ``AUI_TBTOOL_VERT_COUNTERCLOCKWISE``. - """ - - self._orientation = orientation - - - def GetOrientation(self): - """ Returns the toolbar orientation. """ - - return self._orientation - - - def DrawBackground(self, dc, wnd, _rect, horizontal=True): - """ - Draws a toolbar background with a gradient shading. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param Rect `_rect`: the :class:`AuiToolBarItem` rectangle; - :param bool `horizontal`: ``True`` if the toolbar is horizontal, ``False`` if it is vertical. - """ - - rect = wx.Rect(*_rect) - - start_colour = StepColour(self._base_colour, 180) - end_colour = StepColour(self._base_colour, 85) - reflex_colour = StepColour(self._base_colour, 95) - - dc.GradientFillLinear(rect, start_colour, end_colour, - (horizontal and [wx.SOUTH] or [wx.EAST])[0]) - - left = rect.GetLeft() - right = rect.GetRight() - top = rect.GetTop() - bottom = rect.GetBottom() - - dc.SetPen(wx.Pen(reflex_colour)) - if horizontal: - dc.DrawLine(left, bottom, right+1, bottom) - else: - dc.DrawLine(right, top, right, bottom+1) - - - def DrawPlainBackground(self, dc, wnd, _rect): - """ - Draws a toolbar background with a plain colour. - - This method contrasts with the default behaviour of the :class:`AuiToolBar` that - draws a background gradient and this break the window design when putting - it within a control that has margin between the borders and the toolbar - (example: put :class:`AuiToolBar` within a :class:`StaticBoxSizer` that has a plain background). - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param Rect `_rect`: the :class:`AuiToolBarItem` rectangle. - """ - - rect = wx.Rect(*_rect) - rect.height += 1 - - dc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE))) - dc.DrawRectangle(rect.x - 1, rect.y - 1, rect.width + 2, rect.height + 1) - - - def DrawLabel(self, dc, wnd, item, rect): - """ - Draws a toolbar item label. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param `item`: an instance of :class:`AuiToolBarItem`; - :param Rect `rect`: the :class:`AuiToolBarItem` rectangle. - """ - - dc.SetFont(self._font) - - if item.state & AUI_BUTTON_STATE_DISABLED: - dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) - else: - dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNTEXT)) - - orient = item.GetOrientation() - - horizontal = orient == AUI_TBTOOL_HORIZONTAL - # we only care about the text height here since the text - # will get cropped based on the width of the item - label_size = GetLabelSize(dc, item.GetLabel(), not horizontal) - text_width = label_size.GetWidth() - text_height = label_size.GetHeight() - - if orient == AUI_TBTOOL_HORIZONTAL: - text_x = rect.x + (rect.width - text_width) / 2 - text_y = rect.y + (rect.height - text_height) / 2 - dc.DrawText(item.GetLabel(), text_x, text_y) - - elif orient == AUI_TBTOOL_VERT_CLOCKWISE: - text_x = rect.x + (rect.width + text_width) / 2 - text_y = rect.y - dc.DrawRotatedText(item.GetLabel(), text_x, text_y, 270) - - elif AUI_TBTOOL_VERT_COUNTERCLOCKWISE: - text_x = rect.x + (rect.width - text_width) / 2 - text_y = rect.y + text_height - dc.DrawRotatedText(item.GetLabel(), text_x, text_y, 90) - - - def DrawButton(self, dc, wnd, item, rect): - """ - Draws a toolbar item button. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param `item`: an instance of :class:`AuiToolBarItem`; - :param Rect `rect`: the :class:`AuiToolBarItem` rectangle. - """ - - bmp_rect, text_rect = self.GetToolsPosition(dc, item, rect) - - if not item.GetState() & AUI_BUTTON_STATE_DISABLED: - - if item.GetState() & AUI_BUTTON_STATE_PRESSED: - - dc.SetPen(wx.Pen(self._highlight_colour)) - dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 150))) - dc.DrawRectangleRect(rect) - - elif item.GetState() & AUI_BUTTON_STATE_HOVER or item.IsSticky(): - - dc.SetPen(wx.Pen(self._highlight_colour)) - dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170))) - - # draw an even lighter background for checked item hovers (since - # the hover background is the same colour as the check background) - if item.GetState() & AUI_BUTTON_STATE_CHECKED: - dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 180))) - - dc.DrawRectangleRect(rect) - - elif item.GetState() & AUI_BUTTON_STATE_CHECKED: - - # it's important to put this code in an else statment after the - # hover, otherwise hovers won't draw properly for checked items - dc.SetPen(wx.Pen(self._highlight_colour)) - dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170))) - dc.DrawRectangleRect(rect) - - if item.GetState() & AUI_BUTTON_STATE_DISABLED: - bmp = item.GetDisabledBitmap() - else: - bmp = item.GetBitmap() - - if bmp.IsOk(): - dc.DrawBitmap(bmp, bmp_rect.x, bmp_rect.y, True) - else: - # If there is no bitmap to draw, the text can use the whole - # item rect. - text_rect = rect - - # set the item's text colour based on if it is disabled - dc.SetTextForeground(wx.BLACK) - if item.GetState() & AUI_BUTTON_STATE_DISABLED: - dc.SetTextForeground(DISABLED_TEXT_COLOUR) - - if self._agwFlags & AUI_TB_TEXT and item.GetLabel() != "": - self.DrawLabel(dc, wnd, item, text_rect) - - - def DrawDropDownButton(self, dc, wnd, item, rect): - """ - Draws a toolbar dropdown button. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param `item`: an instance of :class:`AuiToolBarItem`; - :param Rect `rect`: the :class:`AuiToolBarItem` rectangle. - """ - - dropbmp_x = dropbmp_y = 0 - - button_rect = wx.Rect(rect.x, rect.y, rect.width-BUTTON_DROPDOWN_WIDTH, rect.height) - dropdown_rect = wx.Rect(rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1, rect.y, BUTTON_DROPDOWN_WIDTH+1, rect.height) - - horizontal = item.GetOrientation() == AUI_TBTOOL_HORIZONTAL - - if horizontal: - button_rect = wx.Rect(rect.x, rect.y, rect.width-BUTTON_DROPDOWN_WIDTH, rect.height) - dropdown_rect = wx.Rect(rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1, rect.y, BUTTON_DROPDOWN_WIDTH+1, rect.height) - else: - button_rect = wx.Rect(rect.x, rect.y, rect.width, rect.height-BUTTON_DROPDOWN_WIDTH) - dropdown_rect = wx.Rect(rect.x, rect.y+rect.height-BUTTON_DROPDOWN_WIDTH-1, rect.width, BUTTON_DROPDOWN_WIDTH+1) - - dropbmp_width = self._button_dropdown_bmp.GetWidth() - dropbmp_height = self._button_dropdown_bmp.GetHeight() - if not horizontal: - tmp = dropbmp_width - dropbmp_width = dropbmp_height - dropbmp_height = tmp - - dropbmp_x = dropdown_rect.x + (dropdown_rect.width/2) - dropbmp_width/2 - dropbmp_y = dropdown_rect.y + (dropdown_rect.height/2) - dropbmp_height/2 - - bmp_rect, text_rect = self.GetToolsPosition(dc, item, button_rect) - - if item.GetState() & AUI_BUTTON_STATE_PRESSED: - - dc.SetPen(wx.Pen(self._highlight_colour)) - dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 140))) - dc.DrawRectangleRect(button_rect) - dc.DrawRectangleRect(dropdown_rect) - - elif item.GetState() & AUI_BUTTON_STATE_HOVER or item.IsSticky(): - - dc.SetPen(wx.Pen(self._highlight_colour)) - dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170))) - dc.DrawRectangleRect(button_rect) - dc.DrawRectangleRect(dropdown_rect) - - elif item.GetState() & AUI_BUTTON_STATE_CHECKED: - # it's important to put this code in an else statment after the - # hover, otherwise hovers won't draw properly for checked items - dc.SetPen(wx.Pen(self._highlight_colour)) - dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170))) - dc.DrawRectangle(button_rect) - dc.DrawRectangle(dropdown_rect) - - if item.GetState() & AUI_BUTTON_STATE_DISABLED: - - bmp = item.GetDisabledBitmap() - dropbmp = self._disabled_button_dropdown_bmp - - else: - - bmp = item.GetBitmap() - dropbmp = self._button_dropdown_bmp - - if not bmp.IsOk(): - return - - dc.DrawBitmap(bmp, bmp_rect.x, bmp_rect.y, True) - if horizontal: - dc.DrawBitmap(dropbmp, dropbmp_x, dropbmp_y, True) - else: - dc.DrawBitmap(wx.BitmapFromImage(dropbmp.ConvertToImage().Rotate90(item.GetOrientation() == AUI_TBTOOL_VERT_CLOCKWISE)), - dropbmp_x, dropbmp_y, True) - - # set the item's text colour based on if it is disabled - dc.SetTextForeground(wx.BLACK) - if item.GetState() & AUI_BUTTON_STATE_DISABLED: - dc.SetTextForeground(DISABLED_TEXT_COLOUR) - - if self._agwFlags & AUI_TB_TEXT and item.GetLabel() != "": - self.DrawLabel(dc, wnd, item, text_rect) - - - def DrawControlLabel(self, dc, wnd, item, rect): - """ - Draws a label for a toolbar control. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param `item`: an instance of :class:`AuiToolBarItem`; - :param Rect `rect`: the :class:`AuiToolBarItem` rectangle. - """ - - label_size = GetLabelSize(dc, item.GetLabel(), item.GetOrientation() != AUI_TBTOOL_HORIZONTAL) - text_height = label_size.GetHeight() - text_width = label_size.GetWidth() - - dc.SetFont(self._font) - - if self._agwFlags & AUI_TB_TEXT: - - tx, text_height = dc.GetTextExtent("ABCDHgj") - - text_width, ty = dc.GetTextExtent(item.GetLabel()) - - # don't draw the label if it is wider than the item width - if text_width > rect.width: - return - - # set the label's text colour - dc.SetTextForeground(wx.BLACK) - - text_x = rect.x + (rect.width/2) - (text_width/2) + 1 - text_y = rect.y + rect.height - text_height - 1 - - if self._agwFlags & AUI_TB_TEXT and item.GetLabel() != "": - dc.DrawText(item.GetLabel(), text_x, text_y) - - - def GetLabelSize(self, dc, wnd, item): - """ - Returns the label size for a toolbar item. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param `item`: an instance of :class:`AuiToolBarItem`. - """ - - dc.SetFont(self._font) - label_size = GetLabelSize(dc, item.GetLabel(), self._orientation != AUI_TBTOOL_HORIZONTAL) - - return wx.Size(item.GetMinSize().GetWidth(), label_size.GetHeight()) - - - def GetToolSize(self, dc, wnd, item): - """ - Returns the toolbar item size. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param `item`: an instance of :class:`AuiToolBarItem`. - """ - - if not item.GetBitmap().IsOk() and not self._agwFlags & AUI_TB_TEXT: - return wx.Size(16, 16) - - width = item.GetBitmap().GetWidth() - height = item.GetBitmap().GetHeight() - - if self._agwFlags & AUI_TB_TEXT: - - dc.SetFont(self._font) - label_size = GetLabelSize(dc, item.GetLabel(), self.GetOrientation() != AUI_TBTOOL_HORIZONTAL) - padding = 6 - - if self._text_orientation == AUI_TBTOOL_TEXT_BOTTOM: - - if self.GetOrientation() != AUI_TBTOOL_HORIZONTAL: - height += 3 # space between top border and bitmap - height += 3 # space between bitmap and text - padding = 0 - - height += label_size.GetHeight() - - if item.GetLabel() != "": - width = max(width, label_size.GetWidth()+padding) - - elif self._text_orientation == AUI_TBTOOL_TEXT_RIGHT and item.GetLabel() != "": - - if self.GetOrientation() == AUI_TBTOOL_HORIZONTAL: - - width += 3 # space between left border and bitmap - width += 3 # space between bitmap and text - padding = 0 - - width += label_size.GetWidth() - height = max(height, label_size.GetHeight()+padding) - - # if the tool has a dropdown button, add it to the width - if item.HasDropDown(): - if item.GetOrientation() == AUI_TBTOOL_HORIZONTAL: - width += BUTTON_DROPDOWN_WIDTH+4 - else: - height += BUTTON_DROPDOWN_WIDTH+4 - - return wx.Size(width, height) - - - def DrawSeparator(self, dc, wnd, _rect): - """ - Draws a toolbar separator. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param Rect `_rect`: the :class:`AuiToolBarItem` rectangle. - """ - - horizontal = True - if self._agwFlags & AUI_TB_VERTICAL: - horizontal = False - - rect = wx.Rect(*_rect) - - if horizontal: - - rect.x += (rect.width/2) - rect.width = 1 - new_height = (rect.height*3)/4 - rect.y += (rect.height/2) - (new_height/2) - rect.height = new_height - - else: - - rect.y += (rect.height/2) - rect.height = 1 - new_width = (rect.width*3)/4 - rect.x += (rect.width/2) - (new_width/2) - rect.width = new_width - - start_colour = StepColour(self._base_colour, 80) - end_colour = StepColour(self._base_colour, 80) - dc.GradientFillLinear(rect, start_colour, end_colour, (horizontal and [wx.SOUTH] or [wx.EAST])[0]) - - - def DrawGripper(self, dc, wnd, rect): - """ - Draws the toolbar gripper. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param Rect `rect`: the :class:`AuiToolBarItem` rectangle. - """ - - i = 0 - while 1: - - if self._agwFlags & AUI_TB_VERTICAL: - - x = rect.x + (i*4) + 4 - y = rect.y + 3 - if x > rect.GetWidth() - 4: - break - - else: - - x = rect.x + 3 - y = rect.y + (i*4) + 4 - if y > rect.GetHeight() - 4: - break - - dc.SetPen(self._gripper_pen1) - dc.DrawPoint(x, y) - dc.SetPen(self._gripper_pen2) - dc.DrawPoint(x, y+1) - dc.DrawPoint(x+1, y) - dc.SetPen(self._gripper_pen3) - dc.DrawPoint(x+2, y+1) - dc.DrawPoint(x+2, y+2) - dc.DrawPoint(x+1, y+2) - - i += 1 - - - def DrawOverflowButton(self, dc, wnd, rect, state): - """ - Draws the overflow button for the :class:`AuiToolBar`. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` derived window; - :param Rect `rect`: the :class:`AuiToolBarItem` rectangle; - :param integer `state`: the overflow button state. - """ - - if state & AUI_BUTTON_STATE_HOVER or state & AUI_BUTTON_STATE_PRESSED: - - cli_rect = wnd.GetClientRect() - light_gray_bg = StepColour(self._highlight_colour, 170) - - if self._agwFlags & AUI_TB_VERTICAL: - - dc.SetPen(wx.Pen(self._highlight_colour)) - dc.DrawLine(rect.x, rect.y, rect.x+rect.width, rect.y) - dc.SetPen(wx.Pen(light_gray_bg)) - dc.SetBrush(wx.Brush(light_gray_bg)) - dc.DrawRectangle(rect.x, rect.y+1, rect.width, rect.height) - - else: - - dc.SetPen(wx.Pen(self._highlight_colour)) - dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height) - dc.SetPen(wx.Pen(light_gray_bg)) - dc.SetBrush(wx.Brush(light_gray_bg)) - dc.DrawRectangle(rect.x+1, rect.y, rect.width, rect.height) - - x = rect.x + 1 + (rect.width-self._overflow_bmp.GetWidth())/2 - y = rect.y + 1 + (rect.height-self._overflow_bmp.GetHeight())/2 - dc.DrawBitmap(self._overflow_bmp, x, y, True) - - - def GetElementSize(self, element_id): - """ - Returns the size of a UI element in the :class:`AuiToolBar`. - - :param integer `element_id`: can be one of the following: - - ==================================== ================================== - Element Identifier Description - ==================================== ================================== - ``AUI_TBART_SEPARATOR_SIZE`` Separator size in :class:`AuiToolBar` - ``AUI_TBART_GRIPPER_SIZE`` Gripper size in :class:`AuiToolBar` - ``AUI_TBART_OVERFLOW_SIZE`` Overflow button size in :class:`AuiToolBar` - ==================================== ================================== - """ - - if element_id == AUI_TBART_SEPARATOR_SIZE: - return self._separator_size - elif element_id == AUI_TBART_GRIPPER_SIZE: - return self._gripper_size - elif element_id == AUI_TBART_OVERFLOW_SIZE: - return self._overflow_size - - return 0 - - - def SetElementSize(self, element_id, size): - """ - Sets the size of a UI element in the :class:`AuiToolBar`. - - :param integer `element_id`: can be one of the following: - - ==================================== ================================== - Element Identifier Description - ==================================== ================================== - ``AUI_TBART_SEPARATOR_SIZE`` Separator size in :class:`AuiToolBar` - ``AUI_TBART_GRIPPER_SIZE`` Gripper size in :class:`AuiToolBar` - ``AUI_TBART_OVERFLOW_SIZE`` Overflow button size in :class:`AuiToolBar` - ==================================== ================================== - - :param integer `size`: the new size of the UI element. - """ - - if element_id == AUI_TBART_SEPARATOR_SIZE: - self._separator_size = size - elif element_id == AUI_TBART_GRIPPER_SIZE: - self._gripper_size = size - elif element_id == AUI_TBART_OVERFLOW_SIZE: - self._overflow_size = size - - - def ShowDropDown(self, wnd, items): - """ - Shows the drop down window menu for overflow items. - - :param `wnd`: an instance of :class:`Window`; - :param list `items`: a list of the overflow toolbar items. - """ - - menuPopup = wx.Menu() - items_added = 0 - - for item in items: - - if item.GetKind() not in [ITEM_SEPARATOR, ITEM_SPACER, ITEM_CONTROL]: - - text = item.GetShortHelp() - if text == "": - text = item.GetLabel() - if text == "": - text = " " - - kind = item.GetKind() - m = wx.MenuItem(menuPopup, item.GetId(), text, item.GetShortHelp(), kind) - orientation = item.GetOrientation() - item.SetOrientation(AUI_TBTOOL_HORIZONTAL) - - if kind not in [ITEM_CHECK, ITEM_RADIO]: - m.SetBitmap(item.GetBitmap()) - - item.SetOrientation(orientation) - - menuPopup.AppendItem(m) - if kind in [ITEM_CHECK, ITEM_RADIO]: - state = (item.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0] - m.Check(state) - - items_added += 1 - - else: - - if items_added > 0 and item.GetKind() == ITEM_SEPARATOR: - menuPopup.AppendSeparator() - - # find out where to put the popup menu of window items - pt = wx.GetMousePosition() - pt = wnd.ScreenToClient(pt) - - # find out the screen coordinate at the bottom of the tab ctrl - cli_rect = wnd.GetClientRect() - pt.y = cli_rect.y + cli_rect.height - - cc = ToolbarCommandCapture() - wnd.PushEventHandler(cc) - - # Adjustments to get slightly better menu placement - if wx.Platform == "__WXMAC__": - pt.y += 5 - pt.x -= 5 - - wnd.PopupMenu(menuPopup, pt) - command = cc.GetCommandId() - wnd.PopEventHandler(True) - - return command - - - def GetToolsPosition(self, dc, item, rect): - """ - Returns the bitmap and text rectangles for a toolbar item. - - :param `dc`: a :class:`DC` device context; - :param `item`: an instance of :class:`AuiToolBarItem`; - :param Rect `rect`: the tool rectangle. - """ - - text_width = text_height = 0 - horizontal = self._orientation == AUI_TBTOOL_HORIZONTAL - text_bottom = self._text_orientation == AUI_TBTOOL_TEXT_BOTTOM - text_right = self._text_orientation == AUI_TBTOOL_TEXT_RIGHT - bmp_width = item.GetBitmap().GetWidth() - bmp_height = item.GetBitmap().GetHeight() - - if self._agwFlags & AUI_TB_TEXT: - dc.SetFont(self._font) - label_size = GetLabelSize(dc, item.GetLabel(), not horizontal) - text_height = label_size.GetHeight() - text_width = label_size.GetWidth() - - bmp_x = bmp_y = text_x = text_y = 0 - - if horizontal and text_bottom: - bmp_x = rect.x + (rect.width/2) - (bmp_width/2) - bmp_y = rect.y + 3 - text_x = rect.x + (rect.width/2) - (text_width/2) - text_y = rect.y + ((bmp_y - rect.y) * 2) + bmp_height - - elif horizontal and text_right: - bmp_x = rect.x + 3 - bmp_y = rect.y + (rect.height/2) - (bmp_height / 2) - text_x = rect.x + ((bmp_x - rect.x) * 2) + bmp_width - text_y = rect.y + (rect.height/2) - (text_height/2) - - elif not horizontal and text_bottom: - bmp_x = rect.x + (rect.width / 2) - (bmp_width / 2) - bmp_y = rect.y + 3 - text_x = rect.x + (rect.width / 2) - (text_width / 2) - text_y = rect.y + ((bmp_y - rect.y) * 2) + bmp_height - - bmp_rect = wx.Rect(bmp_x, bmp_y, bmp_width, bmp_height) - text_rect = wx.Rect(text_x, text_y, text_width, text_height) - - return bmp_rect, text_rect - - -class AuiToolBar(wx.PyControl): - """ - AuiToolBar is a completely owner-drawn toolbar perfectly integrated with the AUI layout system. - This allows drag and drop of toolbars, docking/floating behaviour and the possibility to define - "overflow" items in the toolbar itself. - - The default theme that is used is :class:`AuiDefaultToolBarArt`, which provides a modern, - glossy look and feel. The theme can be changed by calling :meth:`AuiToolBar.SetArtProvider`. - """ - - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, - size=wx.DefaultSize, style=0, agwStyle=AUI_TB_DEFAULT_STYLE): - """ - Default class constructor. - - :param Window `parent`: the :class:`AuiToolBar` parent; - :param integer `id`: an identifier for the control: a value of -1 is taken to mean a default; - :param Point `pos`: the control position. A value of (-1, -1) indicates a default position, - chosen by either the windowing system or wxPython, depending on platform; - :param Size `size`: the control size. A value of (-1, -1) indicates a default size, - chosen by either the windowing system or wxPython, depending on platform; - :param integer `style`: the control window style; - :param integer `agwStyle`: the AGW-specific window style. This can be a combination of the - following bits: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_TB_TEXT`` Shows the text in the toolbar buttons; by default only icons are shown - ``AUI_TB_NO_TOOLTIPS`` Don't show tooltips on :class:`AuiToolBar` items - ``AUI_TB_NO_AUTORESIZE`` Do not auto-resize the :class:`AuiToolBar` - ``AUI_TB_GRIPPER`` Shows a gripper on the :class:`AuiToolBar` - ``AUI_TB_OVERFLOW`` The :class:`AuiToolBar` can contain overflow items - ``AUI_TB_VERTICAL`` The :class:`AuiToolBar` is vertical - ``AUI_TB_HORZ_LAYOUT`` Shows the text and the icons alongside, not vertically stacked. - This style must be used with ``AUI_TB_TEXT`` - ``AUI_TB_PLAIN_BACKGROUND`` Don't draw a gradient background on the toolbar - ``AUI_TB_HORZ_TEXT`` Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT`` - ==================================== ================================== - - The default value for `agwStyle` is: ``AUI_TB_DEFAULT_STYLE`` = 0 - - """ - - wx.PyControl.__init__(self, parent, id, pos, size, style|wx.BORDER_NONE) - - self._sizer = wx.BoxSizer(wx.HORIZONTAL) - self.SetSizer(self._sizer) - self._button_width = -1 - self._button_height = -1 - self._sizer_element_count = 0 - self._action_pos = wx.Point(-1, -1) - self._action_item = None - self._tip_item = None - self._art = AuiDefaultToolBarArt() - self._tool_packing = 2 - self._tool_border_padding = 3 - self._tool_text_orientation = AUI_TBTOOL_TEXT_BOTTOM - self._tool_orientation = AUI_TBTOOL_HORIZONTAL - self._tool_alignment = wx.EXPAND - self._gripper_sizer_item = None - self._overflow_sizer_item = None - self._dragging = False - - self._agwStyle = self._originalStyle = agwStyle - - self._gripper_visible = (self._agwStyle & AUI_TB_GRIPPER and [True] or [False])[0] - self._overflow_visible = (self._agwStyle & AUI_TB_OVERFLOW and [True] or [False])[0] - self._overflow_state = 0 - self._custom_overflow_prepend = [] - self._custom_overflow_append = [] - - self._items = [] - - self.SetMargins(5, 5, 2, 2) - self.SetFont(wx.NORMAL_FONT) - self._art.SetAGWFlags(self._agwStyle) - self.SetExtraStyle(wx.WS_EX_PROCESS_IDLE) - - if agwStyle & AUI_TB_HORZ_LAYOUT: - self.SetToolTextOrientation(AUI_TBTOOL_TEXT_RIGHT) - elif agwStyle & AUI_TB_VERTICAL: - if agwStyle & AUI_TB_CLOCKWISE: - self.SetToolOrientation(AUI_TBTOOL_VERT_CLOCKWISE) - elif agwStyle & AUI_TB_COUNTERCLOCKWISE: - self.SetToolOrientation(AUI_TBTOOL_VERT_COUNTERCLOCKWISE) - - self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) - - self.Bind(wx.EVT_SIZE, self.OnSize) - self.Bind(wx.EVT_IDLE, self.OnIdle) - self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) - self.Bind(wx.EVT_PAINT, self.OnPaint) - 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_RIGHT_DOWN, self.OnRightDown) - self.Bind(wx.EVT_RIGHT_DCLICK, self.OnRightDown) - self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) - self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown) - self.Bind(wx.EVT_MIDDLE_DCLICK, self.OnMiddleDown) - self.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp) - self.Bind(wx.EVT_MOTION, self.OnMotion) - self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) - self.Bind(wx.EVT_SET_CURSOR, self.OnSetCursor) - - - def SetWindowStyleFlag(self, style): - """ - Sets the style of the window. - - :param integer `style`: the new window style. - - :note: Please note that some styles cannot be changed after the window - creation and that `Refresh` might need to be be called after changing the - others for the change to take place immediately. - - :note: Overridden from :class:`PyControl`. - """ - - wx.PyControl.SetWindowStyleFlag(self, style|wx.BORDER_NONE) - - - def SetAGWWindowStyleFlag(self, agwStyle): - """ - Sets the AGW-specific style of the window. - - :param integer `agwStyle`: the new window style. This can be a combination of the - following bits: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_TB_TEXT`` Shows the text in the toolbar buttons; by default only icons are shown - ``AUI_TB_NO_TOOLTIPS`` Don't show tooltips on :class:`AuiToolBar` items - ``AUI_TB_NO_AUTORESIZE`` Do not auto-resize the :class:`AuiToolBar` - ``AUI_TB_GRIPPER`` Shows a gripper on the :class:`AuiToolBar` - ``AUI_TB_OVERFLOW`` The :class:`AuiToolBar` can contain overflow items - ``AUI_TB_VERTICAL`` The :class:`AuiToolBar` is vertical - ``AUI_TB_HORZ_LAYOUT`` Shows the text and the icons alongside, not vertically stacked. - This style must be used with ``AUI_TB_TEXT`` - ``AUI_TB_PLAIN_BACKGROUND`` Don't draw a gradient background on the toolbar - ``AUI_TB_HORZ_TEXT`` Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT`` - ==================================== ================================== - - :note: Please note that some styles cannot be changed after the window - creation and that `Refresh` might need to be be called after changing the - others for the change to take place immediately. - """ - self._agwStyle = self._originalStyle = agwStyle - - if self._art: - self._art.SetAGWFlags(self._agwStyle) - - if agwStyle & AUI_TB_GRIPPER: - self._gripper_visible = True - else: - self._gripper_visible = False - - if agwStyle & AUI_TB_OVERFLOW: - self._overflow_visible = True - else: - self._overflow_visible = False - - if agwStyle & AUI_TB_HORZ_LAYOUT: - self.SetToolTextOrientation(AUI_TBTOOL_TEXT_RIGHT) - else: - self.SetToolTextOrientation(AUI_TBTOOL_TEXT_BOTTOM) - - if agwStyle & AUI_TB_VERTICAL: - if agwStyle & AUI_TB_CLOCKWISE: - self.SetToolOrientation(AUI_TBTOOL_VERT_CLOCKWISE) - elif agwStyle & AUI_TB_COUNTERCLOCKWISE: - self.SetToolOrientation(AUI_TBTOOL_VERT_COUNTERCLOCKWISE) - - - def GetAGWWindowStyleFlag(self): - """ - Returns the AGW-specific window style flag. - - :see: :meth:`SetAGWWindowStyleFlag` for an explanation of various AGW-specific style. - """ - return self._agwStyle - - - def SetArtProvider(self, art): - """ - Instructs :class:`AuiToolBar` to use art provider specified by parameter `art` - for all drawing calls. This allows plugable look-and-feel features. - - :param `art`: an art provider. - - :note: The previous art provider object, if any, will be deleted by :class:`AuiToolBar`. - """ - - del self._art - self._art = art - - if self._art: - self._art.SetAGWFlags(self._agwStyle) - self._art.SetTextOrientation(self._tool_text_orientation) - self._art.SetOrientation(self._tool_orientation) - - - def GetArtProvider(self): - """ Returns the current art provider being used. """ - - return self._art - - def AddSimpleTool(self, tool_id, label, bitmap, short_help_string="", kind=ITEM_NORMAL, target=None): - """ - Adds a tool to the toolbar. This is the simplest method you can use to - ass an item to the :class:`AuiToolBar`. - - :param integer `tool_id`: an integer by which the tool may be identified in subsequent operations; - :param string `label`: the toolbar tool label; - :param Bitmap `bitmap`: the primary tool bitmap; - :param string `short_help_string`: this string is used for the tools tooltip; - :param integer `kind`: the item kind. Can be one of the following: - - ======================== ============================= - Item Kind Description - ======================== ============================= - ``ITEM_CONTROL`` The item in the :class:`AuiToolBar` is a control - ``ITEM_LABEL`` The item in the :class:`AuiToolBar` is a text label - ``ITEM_SPACER`` The item in the :class:`AuiToolBar` is a spacer - ``ITEM_SEPARATOR`` The item in the :class:`AuiToolBar` is a separator - ``ITEM_CHECK`` The item in the :class:`AuiToolBar` is a toolbar check item - ``ITEM_NORMAL`` The item in the :class:`AuiToolBar` is a standard toolbar item - ``ITEM_RADIO`` The item in the :class:`AuiToolBar` is a toolbar radio item - ======================== ============================= - - :param `target`: a custom string indicating that an instance of :class:`~lib.agw.aui.framemanager.AuiPaneInfo` - has been minimized into this toolbar. - """ - - return self.AddTool(tool_id, label, bitmap, wx.NullBitmap, kind, short_help_string, "", None, target) - - - def AddToggleTool(self, tool_id, bitmap, disabled_bitmap, toggle=False, client_data=None, short_help_string="", long_help_string=""): - """ - Adds a toggle tool to the toolbar. - - :param integer `tool_id`: an integer by which the tool may be identified in subsequent operations; - :param Bitmap `bitmap`: the primary tool bitmap; - :param Bitmap `disabled_bitmap`: the bitmap to use when the tool is disabled. If it is equal to - :class:`NullBitmap`, the disabled bitmap is automatically generated by greing the normal one; - :param PyObject `client_data`: whatever Python object to associate with the toolbar item; - :param string `short_help_string`: this string is used for the tools tooltip; - :param string `long_help_string`: this string is shown in the statusbar (if any) of the parent - frame when the mouse pointer is inside the tool. - """ - - kind = (toggle and [ITEM_CHECK] or [ITEM_NORMAL])[0] - return self.AddTool(tool_id, "", bitmap, disabled_bitmap, kind, short_help_string, long_help_string, client_data) - - - def AddTool(self, tool_id, label, bitmap, disabled_bitmap, kind, short_help_string='', long_help_string='', client_data=None, target=None): - """ - Adds a tool to the toolbar. This is the full feature version of :meth:`AddTool`. - - :param integer `tool_id`: an integer by which the tool may be identified in subsequent operations; - :param string `label`: the toolbar tool label; - :param Bitmap `bitmap`: the primary tool bitmap; - :param Bitmap `disabled_bitmap`: the bitmap to use when the tool is disabled. If it is equal to - :class:`NullBitmap`, the disabled bitmap is automatically generated by greing the normal one; - :param integer `kind`: the item kind. Can be one of the following: - - ======================== ============================= - Item Kind Description - ======================== ============================= - ``ITEM_CONTROL`` The item in the :class:`AuiToolBar` is a control - ``ITEM_LABEL`` The item in the :class:`AuiToolBar` is a text label - ``ITEM_SPACER`` The item in the :class:`AuiToolBar` is a spacer - ``ITEM_SEPARATOR`` The item in the :class:`AuiToolBar` is a separator - ``ITEM_CHECK`` The item in the :class:`AuiToolBar` is a toolbar check item - ``ITEM_NORMAL`` The item in the :class:`AuiToolBar` is a standard toolbar item - ``ITEM_RADIO`` The item in the :class:`AuiToolBar` is a toolbar radio item - ======================== ============================= - - :param string `short_help_string`: this string is used for the tools tooltip; - :param string `long_help_string`: this string is shown in the statusbar (if any) of the parent - frame when the mouse pointer is inside the tool. - :param PyObject `client_data`: whatever Python object to associate with the toolbar item. - :param `target`: a custom string indicating that an instance of :class:`~lib.agw.aui.framemanager.AuiPaneInfo` - has been minimized into this toolbar. - """ - - item = AuiToolBarItem() - item.window = None - item.label = label - item.bitmap = bitmap - item.disabled_bitmap = disabled_bitmap - item.short_help = short_help_string - item.long_help = long_help_string - item.target = target - item.active = True - item.dropdown = False - item.spacer_pixels = 0 - - if tool_id == wx.ID_ANY: - tool_id = wx.NewId() - - item.id = tool_id - item.state = 0 - item.proportion = 0 - item.kind = kind - item.sizer_item = None - item.min_size = wx.Size(-1, -1) - item.user_data = 0 - item.sticky = False - item.orientation = self._tool_orientation - - if not item.disabled_bitmap.IsOk(): - # no disabled bitmap specified, we need to make one - if item.bitmap.IsOk(): - item.disabled_bitmap = MakeDisabledBitmap(item.bitmap) - - self._items.append(item) - return self._items[-1] - - - def AddCheckTool(self, tool_id, label, bitmap, disabled_bitmap, short_help_string="", long_help_string="", client_data=None): - """ - Adds a new check (or toggle) tool to the :class:`AuiToolBar`. - - :see: :meth:`AddTool` for an explanation of the input parameters. - """ - - return self.AddTool(tool_id, label, bitmap, disabled_bitmap, ITEM_CHECK, short_help_string, long_help_string, client_data) - - - def AddRadioTool(self, tool_id, label, bitmap, disabled_bitmap, short_help_string="", long_help_string="", client_data=None): - """ - Adds a new radio tool to the toolbar. - - Consecutive radio tools form a radio group such that exactly one button - in the group is pressed at any moment, in other words whenever a button - in the group is pressed the previously pressed button is automatically - released. You should avoid having the radio groups of only one element - as it would be impossible for the user to use such button. - - :note: By default, the first button in the radio group is initially pressed, - the others are not. - - :see: :meth:`AddTool` for an explanation of the input parameters. - """ - - return self.AddTool(tool_id, label, bitmap, disabled_bitmap, ITEM_RADIO, short_help_string, long_help_string, client_data) - - - def AddControl(self, control, label=""): - """ - Adds any control to the toolbar, typically e.g. a :class:`ComboBox`. - - :param Window `control`: the control to be added; - :param string `label`: the label which appears if the control goes into the - overflow items in the toolbar. - """ - - item = AuiToolBarItem() - item.window = control - item.label = label - item.bitmap = wx.NullBitmap - item.disabled_bitmap = wx.NullBitmap - item.active = True - item.dropdown = False - item.spacer_pixels = 0 - item.id = control.GetId() - item.state = 0 - item.proportion = 0 - item.kind = ITEM_CONTROL - item.sizer_item = None - item.min_size = control.GetEffectiveMinSize() - item.user_data = 0 - item.sticky = False - item.orientation = self._tool_orientation - - self._items.append(item) - return self._items[-1] - - - def AddLabel(self, tool_id, label="", width=0): - """ - Adds a label tool to the :class:`AuiToolBar`. - - :param integer `tool_id`: an integer by which the tool may be identified in subsequent operations; - :param string `label`: the toolbar tool label; - :param integer `width`: the tool width. - """ - - min_size = wx.Size(-1, -1) - - if width != -1: - min_size.x = width - - item = AuiToolBarItem() - item.window = None - item.label = label - item.bitmap = wx.NullBitmap - item.disabled_bitmap = wx.NullBitmap - item.active = True - item.dropdown = False - item.spacer_pixels = 0 - - if tool_id == wx.ID_ANY: - tool_id = wx.NewId() - - item.id = tool_id - item.state = 0 - item.proportion = 0 - item.kind = ITEM_LABEL - item.sizer_item = None - item.min_size = min_size - item.user_data = 0 - item.sticky = False - item.orientation = self._tool_orientation - - self._items.append(item) - return self._items[-1] - - - def AddSeparator(self): - """ Adds a separator for spacing groups of tools. """ - - item = AuiToolBarItem() - item.window = None - item.label = "" - item.bitmap = wx.NullBitmap - item.disabled_bitmap = wx.NullBitmap - item.active = True - item.dropdown = False - item.id = -1 - item.state = 0 - item.proportion = 0 - item.kind = ITEM_SEPARATOR - item.sizer_item = None - item.min_size = wx.Size(-1, -1) - item.user_data = 0 - item.sticky = False - item.orientation = self._tool_orientation - - self._items.append(item) - return self._items[-1] - - - def AddSpacer(self, pixels): - """ - Adds a spacer for spacing groups of tools. - - :param integer `pixels`: the width of the spacer. - """ - - item = AuiToolBarItem() - item.window = None - item.label = "" - item.bitmap = wx.NullBitmap - item.disabled_bitmap = wx.NullBitmap - item.active = True - item.dropdown = False - item.spacer_pixels = pixels - item.id = -1 - item.state = 0 - item.proportion = 0 - item.kind = ITEM_SPACER - item.sizer_item = None - item.min_size = wx.Size(-1, -1) - item.user_data = 0 - item.sticky = False - item.orientation = self._tool_orientation - - self._items.append(item) - return self._items[-1] - - - def AddStretchSpacer(self, proportion=1): - """ - Adds a stretchable spacer for spacing groups of tools. - - :param integer `proportion`: the stretchable spacer proportion. - """ - - item = AuiToolBarItem() - item.window = None - item.label = "" - item.bitmap = wx.NullBitmap - item.disabled_bitmap = wx.NullBitmap - item.active = True - item.dropdown = False - item.spacer_pixels = 0 - item.id = -1 - item.state = 0 - item.proportion = proportion - item.kind = ITEM_SPACER - item.sizer_item = None - item.min_size = wx.Size(-1, -1) - item.user_data = 0 - item.sticky = False - item.orientation = self._tool_orientation - - self._items.append(item) - return self._items[-1] - - - def Clear(self): - """ Deletes all the tools in the :class:`AuiToolBar`. """ - - self._items = [] - self._sizer_element_count = 0 - - - def ClearTools(self): - """ Deletes all the tools in the :class:`AuiToolBar`. """ - - self.Clear() - - - def DeleteTool(self, tool_id): - """ - Removes the specified tool from the toolbar and deletes it. - - :param integer `tool_id`: the :class:`AuiToolBarItem` identifier. - - :returns: ``True`` if the tool was deleted, ``False`` otherwise. - - :note: Note that it is unnecessary to call :meth:`Realize` for the change to - take place, it will happen immediately. - """ - - idx = self.GetToolIndex(tool_id) - - if idx >= 0 and idx < len(self._items): - self._items.pop(idx) - self.Realize() - return True - - return False - - - def DeleteToolByPos(self, pos): - """ - This function behaves like :meth:`DeleteTool` but it deletes the tool at the specified position and not the one with the given id. - - :param integer `pos`: the tool position. - - :see: :meth:`~AuiToolBar.DeleteTool` - """ - - if pos >= 0 and pos < len(self._items): - - self._items.pop(pos) - self.Realize() - return True - - return False - - - def FindControl(self, id): - """ - Returns a pointer to the control identified by `id` or ``None`` if no corresponding control is found. - - :param integer `id`: the control identifier. - """ - - wnd = self.FindWindow(id) - return wnd - - - def FindTool(self, tool_id): - """ - Finds a tool for the given tool id. - - :param integer `tool_id`: the :class:`AuiToolBarItem` identifier. - """ - - for item in self._items: - if item.id == tool_id: - return item - - return None - - - def FindToolByLabel(self, label): - """ - Finds a tool for the given label. - - :param string `label`: the :class:`AuiToolBarItem` label. - """ - - for item in self._items: - if item.label == label: - return item - - return None - - - def FindToolForPosition(self, x, y): - """ - Finds a tool for the given mouse position. - - :param integer `x`: mouse `x` position; - :param integer `y`: mouse `y` position. - - :returns: a pointer to a :class:`AuiToolBarItem` if a tool is found, or ``None`` otherwise. - """ - - for i, item in enumerate(self._items): - if not item.sizer_item: - continue - - rect = item.sizer_item.GetRect() - if rect.Contains((x,y)): - - # if the item doesn't fit on the toolbar, return None - if not self.GetToolFitsByIndex(i): - return None - - return item - - return None - - - def HitTest(self, x, y): - """ - Finds a tool for the given mouse position. - - :param integer `x`: mouse `x` screen position; - :param integer `y`: mouse `y` screen position. - - :returns: a pointer to a :class:`AuiToolBarItem` if a tool is found, or ``None`` otherwise. - - :note: This method is similar to :meth:`FindToolForPosition` but it works with absolute coordinates. - """ - - return self.FindToolForPosition(*self.ScreenToClient((x,y))) - - - def FindToolForPositionWithPacking(self, x, y): - """ - Finds a tool for the given mouse position, taking into account also the tool packing. - - :param integer `x`: mouse `x` position; - :param integer `y`: mouse `y` position. - - :returns: a pointer to a :class:`AuiToolBarItem` if a tool is found, or ``None`` otherwise. - """ - - count = len(self._items) - - for i, item in enumerate(self._items): - if not item.sizer_item: - continue - - rect = item.sizer_item.GetRect() - - # apply tool packing - if i+1 < count: - rect.width += self._tool_packing - - if rect.Contains((x,y)): - - # if the item doesn't fit on the toolbar, return None - if not self.GetToolFitsByIndex(i): - return None - - return item - - return None - - - def FindToolByIndex(self, pos): - """ - Finds a tool for the given tool position in the :class:`AuiToolBar`. - - :param integer `pos`: the tool position in the toolbar. - - :returns: a pointer to a :class:`AuiToolBarItem` if a tool is found, or ``None`` otherwise. - """ - - if pos < 0 or pos >= len(self._items): - return None - - return self._items[pos] - - - def SetToolBitmapSize(self, size): - """ - Sets the default size of each tool bitmap. The default bitmap size is 16 by 15 pixels. - - :param Size `size`: the size of the bitmaps in the toolbar. - - :note: This should be called to tell the toolbar what the tool bitmap - size is. Call it before you add tools. - - :note: Note that this is the size of the bitmap you pass to :meth:`AddTool`, - and not the eventual size of the tool button. - - .. todo:: - - Add :class:`ToolBar` compatibility, actually implementing this method. - - """ - - # TODO: wx.ToolBar compatibility - pass - - - def GetToolBitmapSize(self): - """ - Returns the size of bitmap that the toolbar expects to have. The default bitmap size is 16 by 15 pixels. - - :note: Note that this is the size of the bitmap you pass to :meth:`AddTool`, - and not the eventual size of the tool button. - - .. todo:: - - Add :class:`ToolBar` compatibility, actually implementing this method. - - """ - - # TODO: wx.ToolBar compatibility - return wx.Size(16, 15) - - - def SetToolProportion(self, tool_id, proportion): - """ - Sets the tool proportion in the toolbar. - - :param integer `tool_id`: the :class:`AuiToolBarItem` identifier; - :param integer `proportion`: the tool proportion in the toolbar. - """ - - item = self.FindTool(tool_id) - if not item: - return - - item.proportion = proportion - - - def GetToolProportion(self, tool_id): - """ - Returns the tool proportion in the toolbar. - - :param integer `tool_id`: the :class:`AuiToolBarItem` identifier. - """ - - item = self.FindTool(tool_id) - if not item: - return - - return item.proportion - - - def SetToolSeparation(self, separation): - """ - Sets the separator size for the toolbar. - - :param integer `separation`: the separator size in pixels. - """ - - if self._art: - self._art.SetElementSize(AUI_TBART_SEPARATOR_SIZE, separation) - - - def GetToolSeparation(self): - """ Returns the separator size for the toolbar, in pixels. """ - - if self._art: - return self._art.GetElementSize(AUI_TBART_SEPARATOR_SIZE) - - return 5 - - - def SetToolDropDown(self, tool_id, dropdown): - """ - Assigns a drop down window menu to the toolbar item. - - :param integer `tool_id`: the :class:`AuiToolBarItem` identifier; - :param bool `dropdown`: whether to assign a drop down menu or not. - """ - - item = self.FindTool(tool_id) - if not item: - return - - item.dropdown = dropdown - - - def GetToolDropDown(self, tool_id): - """ - Returns whether the toolbar item identified by `tool_id` has an associated drop down window menu or not. - - :param integer `tool_id`: the :class:`AuiToolBarItem` identifier. - """ - - item = self.FindTool(tool_id) - if not item: - return - - return item.dropdown - - - def SetToolSticky(self, tool_id, sticky): - """ - Sets the toolbar item as sticky or non-sticky. - - :param integer `tool_id`: the :class:`AuiToolBarItem` identifier; - :param bool `sticky`: whether the tool should be sticky or not. - """ - - # ignore separators - if tool_id == -1: - return - - item = self.FindTool(tool_id) - if not item: - return - - if item.sticky == sticky: - return - - item.sticky = sticky - - self.Refresh(False) - self.Update() - - - def GetToolSticky(self, tool_id): - """ - Returns whether the toolbar item identified by `tool_id` has a sticky behaviour or not. - - :param integer `tool_id`: the :class:`AuiToolBarItem` identifier. - """ - - item = self.FindTool(tool_id) - if not item: - return - - return item.sticky - - - def SetToolBorderPadding(self, padding): - """ - Sets the padding between the tool border and the label. - - :param integer `padding`: the padding in pixels. - """ - - self._tool_border_padding = padding - - - def GetToolBorderPadding(self): - """ Returns the padding between the tool border and the label, in pixels. """ - - return self._tool_border_padding - - - def SetToolTextOrientation(self, orientation): - """ - Sets the label orientation for the toolbar items. - - :param integer `orientation`: the :class:`AuiToolBarItem` label orientation. - """ - - self._tool_text_orientation = orientation - - if self._art: - self._art.SetTextOrientation(orientation) - - - def GetToolTextOrientation(self): - """ Returns the label orientation for the toolbar items. """ - - return self._tool_text_orientation - - - def SetToolOrientation(self, orientation): - """ - Sets the tool orientation for the toolbar items. - - :param integer `orientation`: the :class:`AuiToolBarItem` orientation. - """ - - self._tool_orientation = orientation - if self._art: - self._art.SetOrientation(orientation) - - - def GetToolOrientation(self): - """ Returns the orientation for the toolbar items. """ - - return self._tool_orientation - - - def SetToolPacking(self, packing): - """ - Sets the value used for spacing tools. The default value is 1 pixel. - - :param integer `packing`: the value for packing. - """ - - self._tool_packing = packing - - - def GetToolPacking(self): - """ Returns the value used for spacing tools. The default value is 1 pixel. """ - - return self._tool_packing - - - def SetOrientation(self, orientation): - """ - Sets the toolbar orientation. - - :param integer `orientation`: either ``wx.VERTICAL`` or ``wx.HORIZONTAL``. - - :note: This can be temporarily overridden by :class:`~lib.agw.aui.framemanager.AuiManager` when floating and - docking a :class:`AuiToolBar`. - """ - - pass - - - def SetMargins(self, left=-1, right=-1, top=-1, bottom=-1): - """ - Set the values to be used as margins for the toolbar. - - :param integer `left`: the left toolbar margin; - :param integer `right`: the right toolbar margin; - :param integer `top`: the top toolbar margin; - :param integer `bottom`: the bottom toolbar margin. - """ - - if left != -1: - self._left_padding = left - if right != -1: - self._right_padding = right - if top != -1: - self._top_padding = top - if bottom != -1: - self._bottom_padding = bottom - - - def SetMarginsSize(self, size): - """ - Set the values to be used as margins for the toolbar. - - :param Size `size`: the margin size (an instance of :class:`Size`). - """ - - self.SetMargins(size.x, size.x, size.y, size.y) - - - def SetMarginsXY(self, x, y): - """ - Set the values to be used as margins for the toolbar. - - :param integer `x`: left margin, right margin and inter-tool separation value; - :param integer `y`: top margin, bottom margin and inter-tool separation value. - """ - - self.SetMargins(x, x, y, y) - - - def GetGripperVisible(self): - """ Returns whether the toolbar gripper is visible or not. """ - - return self._gripper_visible - - - def SetGripperVisible(self, visible): - """ - Sets whether the toolbar gripper is visible or not. - - :param bool `visible`: ``True`` for a visible gripper, ``False`` otherwise. - """ - - self._gripper_visible = visible - if visible: - self._agwStyle |= AUI_TB_GRIPPER - else: - self._agwStyle &= ~AUI_TB_GRIPPER - - self.Realize() - self.Refresh(False) - - - def GetOverflowVisible(self): - """ Returns whether the overflow button is visible or not. """ - - return self._overflow_visible - - - def SetOverflowVisible(self, visible): - """ - Sets whether the overflow button is visible or not. - - :param bool `visible`: ``True`` for a visible overflow button, ``False`` otherwise. - """ - - self._overflow_visible = visible - if visible: - self._agwStyle |= AUI_TB_OVERFLOW - else: - self._agwStyle &= ~AUI_TB_OVERFLOW - - self.Refresh(False) - - - def SetFont(self, font): - """ - Sets the :class:`AuiToolBar` font. - - :param Font `font`: the new toolbar font. - - :note: Overridden from :class:`PyControl`. - """ - - res = wx.PyControl.SetFont(self, font) - - if self._art: - self._art.SetFont(font) - - return res - - - def SetHoverItem(self, pitem): - """ - Sets a toolbar item to be currently hovered by the mouse. - - :param `pitem`: an instance of :class:`AuiToolBarItem`. - """ - - former_hover = None - - for item in self._items: - - if item.state & AUI_BUTTON_STATE_HOVER: - former_hover = item - - item.state &= ~AUI_BUTTON_STATE_HOVER - - if pitem: - pitem.state |= AUI_BUTTON_STATE_HOVER - - if former_hover != pitem: - self.Refresh(False) - self.Update() - - - def SetPressedItem(self, pitem): - """ - Sets a toolbar item to be currently in a "pressed" state. - - :param `pitem`: an instance of :class:`AuiToolBarItem`. - """ - - former_item = None - - for item in self._items: - - if item.state & AUI_BUTTON_STATE_PRESSED: - former_item = item - - item.state &= ~AUI_BUTTON_STATE_PRESSED - - if pitem: - pitem.state &= ~AUI_BUTTON_STATE_HOVER - pitem.state |= AUI_BUTTON_STATE_PRESSED - - if former_item != pitem: - self.Refresh(False) - self.Update() - - - def RefreshOverflowState(self): - """ Refreshes the overflow button. """ - - if not self._overflow_sizer_item: - self._overflow_state = 0 - return - - overflow_state = 0 - overflow_rect = self.GetOverflowRect() - - # find out the mouse's current position - pt = wx.GetMousePosition() - pt = self.ScreenToClient(pt) - - # find out if the mouse cursor is inside the dropdown rectangle - if overflow_rect.Contains((pt.x, pt.y)): - - if _VERSION_STRING < "2.9": - leftDown = wx.GetMouseState().LeftDown() - else: - leftDown = wx.GetMouseState().LeftIsDown() - - if leftDown: - overflow_state = AUI_BUTTON_STATE_PRESSED - else: - overflow_state = AUI_BUTTON_STATE_HOVER - - if overflow_state != self._overflow_state: - self._overflow_state = overflow_state - self.Refresh(False) - self.Update() - - self._overflow_state = overflow_state - - - def ToggleTool(self, tool_id, state): - """ - Toggles a tool on or off. This does not cause any event to get emitted. - - :param integer `tool_id`: tool in question. - :param bool `state`: if ``True``, toggles the tool on, otherwise toggles it off. - - :note: This only applies to a tool that has been specified as a toggle tool. - """ - tool = self.FindTool(tool_id) - if tool: - if tool.kind == ITEM_RADIO: - if state and not (tool.state & AUI_BUTTON_STATE_CHECKED): - tool.state |= AUI_BUTTON_STATE_CHECKED - items = self._items - index = items.index(tool) - for item in items[index + 1:]: - if item.kind != ITEM_RADIO: - break - item.state &= ~AUI_BUTTON_STATE_CHECKED - for item in reversed(items[:index]): - if item.kind != ITEM_RADIO: - break - item.state &= ~AUI_BUTTON_STATE_CHECKED - elif tool.kind == ITEM_CHECK: - if state: - tool.state |= AUI_BUTTON_STATE_CHECKED - else: - tool.state &= ~AUI_BUTTON_STATE_CHECKED - - def GetToolToggled(self, tool_id): - """ - Returns whether a tool is toggled or not. - - :param integer `tool_id`: the toolbar item identifier. - - :note: This only applies to a tool that has been specified as a toggle tool. - """ - - tool = self.FindTool(tool_id) - - if tool: - if tool.kind not in [ITEM_CHECK, ITEM_RADIO]: - return False - - return (tool.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0] - - return False - - - def EnableTool(self, tool_id, state): - """ - Enables or disables the tool. - - :param integer `tool_id`: identifier for the tool to enable or disable. - :param bool `state`: if ``True``, enables the tool, otherwise disables it. - """ - - tool = self.FindTool(tool_id) - - if tool: - - if state: - tool.state &= ~AUI_BUTTON_STATE_DISABLED - else: - tool.state |= AUI_BUTTON_STATE_DISABLED - - - def GetToolEnabled(self, tool_id): - """ - Returns whether the tool identified by `tool_id` is enabled or not. - - :param integer `tool_id`: the tool identifier. - """ - - tool = self.FindTool(tool_id) - - if tool: - return (tool.state & AUI_BUTTON_STATE_DISABLED and [False] or [True])[0] - - return False - - - def GetToolLabel(self, tool_id): - """ - Returns the tool label for the tool identified by `tool_id`. - - :param integer `tool_id`: the tool identifier. - """ - - tool = self.FindTool(tool_id) - if not tool: - return "" - - return tool.label - - - def SetToolLabel(self, tool_id, label): - """ - Sets the tool label for the tool identified by `tool_id`. - - :param integer `tool_id`: the tool identifier; - :param string `label`: the new toolbar item label. - """ - - tool = self.FindTool(tool_id) - if tool: - tool.label = label - - - def GetToolBitmap(self, tool_id): - """ - Returns the tool bitmap for the tool identified by `tool_id`. - - :param integer `tool_id`: the tool identifier. - """ - - tool = self.FindTool(tool_id) - if not tool: - return wx.NullBitmap - - return tool.bitmap - - - def SetToolBitmap(self, tool_id, bitmap): - """ - Sets the tool bitmap for the tool identified by `tool_id`. - - :param integer `tool_id`: the tool identifier; - :param Bitmap `bitmap`: the new bitmap for the toolbar item. - """ - - tool = self.FindTool(tool_id) - if tool: - tool.bitmap = bitmap - - - def SetToolNormalBitmap(self, tool_id, bitmap): - """ - Sets the tool bitmap for the tool identified by `tool_id`. - - :param integer `tool_id`: the tool identifier; - :param Bitmap `bitmap`: the new bitmap for the toolbar item. - """ - - self.SetToolBitmap(tool_id, bitmap) - - - def SetToolDisabledBitmap(self, tool_id, bitmap): - """ - Sets the tool disabled bitmap for the tool identified by `tool_id`. - - :param integer `tool_id`: the tool identifier; - :param Bitmap `bitmap`: the new disabled bitmap for the toolbar item. - """ - - tool = self.FindTool(tool_id) - if tool: - tool.disabled_bitmap = bitmap - - - def GetToolShortHelp(self, tool_id): - """ - Returns the short help for the given tool. - - :param integer `tool_id`: the tool identifier. - """ - - tool = self.FindTool(tool_id) - if not tool: - return "" - - return tool.short_help - - - def SetToolShortHelp(self, tool_id, help_string): - """ - Sets the short help for the given tool. - - :param integer `tool_id`: the tool identifier; - :param string `help_string`: the string for the short help. - """ - - tool = self.FindTool(tool_id) - if tool: - tool.short_help = help_string - - - def GetToolLongHelp(self, tool_id): - """ - Returns the long help for the given tool. - - :param integer `tool_id`: the tool identifier. - """ - - tool = self.FindTool(tool_id) - if not tool: - return "" - - return tool.long_help - - - def SetToolAlignment(self, alignment=wx.EXPAND): - """ - This sets the alignment for all of the tools within the toolbar - (only has an effect when the toolbar is expanded). - - :param integer `alignment`: :class:`Sizer` alignment value - (``wx.ALIGN_CENTER_HORIZONTAL`` or ``wx.ALIGN_CENTER_VERTICAL``). - """ - - self._tool_alignment = alignment - - - - def SetToolLongHelp(self, tool_id, help_string): - """ - Sets the long help for the given tool. - - :param integer `tool_id`: the tool identifier; - :param string `help_string`: the string for the long help. - """ - - tool = self.FindTool(tool_id) - if tool: - tool.long_help = help_string - - - def SetCustomOverflowItems(self, prepend, append): - """ - Sets the two lists `prepend` and `append` as custom overflow items. - - :param list `prepend`: a list of :class:`AuiToolBarItem` to be prepended; - :param list `append`: a list of :class:`AuiToolBarItem` to be appended. - """ - - self._custom_overflow_prepend = prepend - self._custom_overflow_append = append - - - def GetToolCount(self): - """ Returns the number of tools in the :class:`AuiToolBar`. """ - - return len(self._items) - - - def GetToolIndex(self, tool_id): - """ - Returns the position of the tool in the toolbar given its identifier. - - :param integer `tool_id`: the toolbar item identifier. - """ - - # this will prevent us from returning the index of the - # first separator in the toolbar since its id is equal to -1 - if tool_id == -1: - return wx.NOT_FOUND - - for i, item in enumerate(self._items): - if item.id == tool_id: - return i - - return wx.NOT_FOUND - - - def GetToolPos(self, tool_id): - """ - Returns the position of the tool in the toolbar given its identifier. - - :param integer `tool_id`: the toolbar item identifier. - """ - - return self.GetToolIndex(tool_id) - - - def GetToolFitsByIndex(self, tool_id): - """ - Returns whether the tool identified by `tool_id` fits into the toolbar or not. - - :param integer `tool_id`: the toolbar item identifier. - """ - - if tool_id < 0 or tool_id >= len(self._items): - return False - - if not self._items[tool_id].sizer_item: - return False - - cli_w, cli_h = self.GetClientSize() - rect = self._items[tool_id].sizer_item.GetRect() - - if self._agwStyle & AUI_TB_VERTICAL: - # take the dropdown size into account - if self._overflow_visible: - cli_h -= self._overflow_sizer_item.GetSize().y - - if rect.y+rect.height < cli_h: - return True - - else: - - # take the dropdown size into account - if self._overflow_visible: - cli_w -= self._overflow_sizer_item.GetSize().x - - if rect.x+rect.width < cli_w: - return True - - return False - - - def GetToolFits(self, tool_id): - """ - Returns whether the tool identified by `tool_id` fits into the toolbar or not. - - :param integer `tool_id`: the toolbar item identifier. - """ - - return self.GetToolFitsByIndex(self.GetToolIndex(tool_id)) - - - def GetToolRect(self, tool_id): - """ - Returns the toolbar item rectangle - - :param integer `tool_id`: the toolbar item identifier. - """ - - tool = self.FindTool(tool_id) - if tool and tool.sizer_item: - return tool.sizer_item.GetRect() - - return wx.Rect() - - - def GetToolBarFits(self): - """ Returns whether the :class:`AuiToolBar` size fits in a specified size. """ - - if len(self._items) == 0: - # empty toolbar always 'fits' - return True - - # entire toolbar content fits if the last tool fits - return self.GetToolFitsByIndex(len(self._items) - 1) - - - def Realize(self): - """ Realizes the toolbar. This function should be called after you have added tools. """ - - dc = wx.ClientDC(self) - - if not dc.IsOk(): - return False - - horizontal = True - if self._agwStyle & AUI_TB_VERTICAL: - horizontal = False - - # create the new sizer to add toolbar elements to - sizer = wx.BoxSizer((horizontal and [wx.HORIZONTAL] or [wx.VERTICAL])[0]) - - # add gripper area - separator_size = self._art.GetElementSize(AUI_TBART_SEPARATOR_SIZE) - gripper_size = self._art.GetElementSize(AUI_TBART_GRIPPER_SIZE) - - if gripper_size > 0 and self._gripper_visible: - if horizontal: - self._gripper_sizer_item = sizer.Add((gripper_size, 1), 0, wx.EXPAND) - else: - self._gripper_sizer_item = sizer.Add((1, gripper_size), 0, wx.EXPAND) - else: - self._gripper_sizer_item = None - - # add "left" padding - if self._left_padding > 0: - if horizontal: - sizer.Add((self._left_padding, 1)) - else: - sizer.Add((1, self._left_padding)) - - count = len(self._items) - for i, item in enumerate(self._items): - - sizer_item = None - kind = item.kind - - if kind == ITEM_LABEL: - - size = self._art.GetLabelSize(dc, self, item) - sizer_item = sizer.Add((size.x + (self._tool_border_padding*2), - size.y + (self._tool_border_padding*2)), - item.proportion, - item.alignment) - if i+1 < count: - sizer.AddSpacer(self._tool_packing) - - - elif kind in [ITEM_CHECK, ITEM_NORMAL, ITEM_RADIO]: - - size = self._art.GetToolSize(dc, self, item) - sizer_item = sizer.Add((size.x + (self._tool_border_padding*2), - size.y + (self._tool_border_padding*2)), - 0, - item.alignment) - # add tool packing - if i+1 < count: - sizer.AddSpacer(self._tool_packing) - - elif kind == ITEM_SEPARATOR: - - if horizontal: - sizer_item = sizer.Add((separator_size, 1), 0, wx.EXPAND) - else: - sizer_item = sizer.Add((1, separator_size), 0, wx.EXPAND) - - # add tool packing - if i+1 < count: - sizer.AddSpacer(self._tool_packing) - - elif kind == ITEM_SPACER: - - if item.proportion > 0: - sizer_item = sizer.AddStretchSpacer(item.proportion) - else: - sizer_item = sizer.Add((item.spacer_pixels, 1)) - - elif kind == ITEM_CONTROL: - - vert_sizer = wx.BoxSizer(wx.VERTICAL) - vert_sizer.AddStretchSpacer(1) - ctrl_sizer_item = vert_sizer.Add(item.window, 0, wx.EXPAND) - vert_sizer.AddStretchSpacer(1) - - if self._agwStyle & AUI_TB_TEXT and \ - self._tool_text_orientation == AUI_TBTOOL_TEXT_BOTTOM and \ - item.GetLabel() != "": - - s = self.GetLabelSize(item.GetLabel()) - vert_sizer.Add((1, s.y)) - - sizer_item = sizer.Add(vert_sizer, item.proportion, wx.EXPAND) - min_size = item.min_size - - # proportional items will disappear from the toolbar if - # their min width is not set to something really small - if item.proportion != 0: - min_size.x = 1 - - if min_size.IsFullySpecified(): - sizer.SetItemMinSize(vert_sizer, min_size) - vert_sizer.SetItemMinSize(item.window, min_size) - - # add tool packing - if i+1 < count: - sizer.AddSpacer(self._tool_packing) - - item.sizer_item = sizer_item - - - # add "right" padding - if self._right_padding > 0: - if horizontal: - sizer.Add((self._right_padding, 1)) - else: - sizer.Add((1, self._right_padding)) - - # add drop down area - self._overflow_sizer_item = None - if self._agwStyle & AUI_TB_OVERFLOW: - overflow_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE) - if overflow_size > 0 and self._overflow_visible: - if horizontal: - self._overflow_sizer_item = sizer.Add((overflow_size, 1), 0, wx.EXPAND) - else: - self._overflow_sizer_item = sizer.Add((1, overflow_size), 0, wx.EXPAND) - else: - self._overflow_sizer_item = None - - # the outside sizer helps us apply the "top" and "bottom" padding - outside_sizer = wx.BoxSizer((horizontal and [wx.VERTICAL] or [wx.HORIZONTAL])[0]) - - # add "top" padding - if self._top_padding > 0: - - if horizontal: - outside_sizer.Add((1, self._top_padding)) - else: - outside_sizer.Add((self._top_padding, 1)) - - # add the sizer that contains all of the toolbar elements - outside_sizer.Add(sizer, 1, self._tool_alignment) - - # add "bottom" padding - if self._bottom_padding > 0: - - if horizontal: - outside_sizer.Add((1, self._bottom_padding)) - else: - outside_sizer.Add((self._bottom_padding, 1)) - - del self._sizer # remove old sizer - self._sizer = outside_sizer - self.SetSizer(outside_sizer) - - # calculate the rock-bottom minimum size - for item in self._items: - - if item.sizer_item and item.proportion > 0 and item.min_size.IsFullySpecified(): - item.sizer_item.SetMinSize((0, 0)) - - self._absolute_min_size = self._sizer.GetMinSize() - - # reset the min sizes to what they were - for item in self._items: - - if item.sizer_item and item.proportion > 0 and item.min_size.IsFullySpecified(): - item.sizer_item.SetMinSize(item.min_size) - - # set control size - size = self._sizer.GetMinSize() - self.SetMinSize(size) - self._minWidth = size.x - self._minHeight = size.y - - if self._agwStyle & AUI_TB_NO_AUTORESIZE == 0: - - cur_size = self.GetClientSize() - new_size = self.GetMinSize() - - if new_size != cur_size: - - self.SetClientSize(new_size) - - else: - - self._sizer.SetDimension(0, 0, cur_size.x, cur_size.y) - - else: - - cur_size = self.GetClientSize() - self._sizer.SetDimension(0, 0, cur_size.x, cur_size.y) - - self.Refresh(False) - return True - - def GetOverflowState(self): - """ Returns the state of the overflow button. """ - - return self._overflow_state - - def GetOverflowRect(self): - """ Returns the rectangle of the overflow button. """ - - cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize()) - overflow_rect = wx.Rect(*self._overflow_sizer_item.GetRect()) - overflow_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE) - - if self._agwStyle & AUI_TB_VERTICAL: - - overflow_rect.y = cli_rect.height - overflow_size - overflow_rect.x = 0 - overflow_rect.width = cli_rect.width - overflow_rect.height = overflow_size - - else: - - overflow_rect.x = cli_rect.width - overflow_size - overflow_rect.y = 0 - overflow_rect.width = overflow_size - overflow_rect.height = cli_rect.height - - return overflow_rect - - - def GetLabelSize(self, label): - """ - Returns the standard size of a toolbar item. - - :param string `label`: a test label. - """ - - dc = wx.ClientDC(self) - dc.SetFont(self._font) - - return GetLabelSize(dc, label, self._tool_orientation != AUI_TBTOOL_HORIZONTAL) - - - def GetAuiManager(self): - """ Returns the :class:`~lib.agw.aui.framemanager.AuiManager` which manages the toolbar. """ - - return getattr(self, '_auiManager', None) - - - def SetAuiManager(self, auiManager): - """ Sets the :class:`~lib.agw.aui.framemanager.AuiManager` which manages the toolbar. """ - - self._auiManager = auiManager - - - def DoIdleUpdate(self): - """ Updates the toolbar during idle times. """ - - handler = self.GetEventHandler() - if not handler: - return - - need_refresh = False - - for item in self._items: - - if item.id == -1: - continue - - evt = wx.UpdateUIEvent(item.id) - evt.SetEventObject(self) - - if handler.ProcessEvent(evt): - - if evt.GetSetEnabled(): - - if item.window: - is_enabled = item.window.IsEnabled() - else: - is_enabled = (item.state & AUI_BUTTON_STATE_DISABLED and [False] or [True])[0] - - new_enabled = evt.GetEnabled() - if new_enabled != is_enabled: - - if item.window: - item.window.Enable(new_enabled) - else: - if new_enabled: - item.state &= ~AUI_BUTTON_STATE_DISABLED - else: - item.state |= AUI_BUTTON_STATE_DISABLED - - need_refresh = True - - if evt.GetSetChecked(): - - # make sure we aren't checking an item that can't be - if item.kind != ITEM_CHECK and item.kind != ITEM_RADIO: - continue - - is_checked = (item.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0] - new_checked = evt.GetChecked() - - if new_checked != is_checked: - - if new_checked: - item.state |= AUI_BUTTON_STATE_CHECKED - else: - item.state &= ~AUI_BUTTON_STATE_CHECKED - - need_refresh = True - - if need_refresh: - self.Refresh(False) - - - def OnSize(self, event): - """ - Handles the ``wx.EVT_SIZE`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`SizeEvent` event to be processed. - """ - x, y = self.GetClientSize() - realize = False - - if (x >= y and self._absolute_min_size.x > x) or (y > x and self._absolute_min_size.y > y): - # hide all flexible items - for item in self._items: - if item.sizer_item and item.proportion > 0 and item.sizer_item.IsShown(): - item.sizer_item.Show(False) - item.sizer_item.SetProportion(0) - - if self._originalStyle & AUI_TB_OVERFLOW: - if not self.GetOverflowVisible(): - self.SetOverflowVisible(True) - realize = True - - else: - if self._originalStyle & AUI_TB_OVERFLOW and not self._custom_overflow_append and \ - not self._custom_overflow_prepend: - if self.GetOverflowVisible(): - self.SetOverflowVisible(False) - realize = True - - # show all flexible items - for item in self._items: - if item.sizer_item and item.proportion > 0 and not item.sizer_item.IsShown(): - item.sizer_item.Show(True) - item.sizer_item.SetProportion(item.proportion) - - self._sizer.SetDimension(0, 0, x, y) - - if realize: - self.Realize() - else: - self.Refresh(False) - - self.Update() - - - def DoSetSize(self, x, y, width, height, sizeFlags=wx.SIZE_AUTO): - """ - Sets the position and size of the window in pixels. The `sizeFlags` - parameter indicates the interpretation of the other params if they are - equal to -1. - - :param integer `x`: the window `x` position; - :param integer `y`: the window `y` position; - :param integer `width`: the window width; - :param integer `height`: the window height; - :param integer `sizeFlags`: may have one of this bit set: - - =================================== ====================================== - Size Flags Description - =================================== ====================================== - ``wx.SIZE_AUTO`` A -1 indicates that a class-specific default should be used. - ``wx.SIZE_AUTO_WIDTH`` A -1 indicates that a class-specific default should be used for the width. - ``wx.SIZE_AUTO_HEIGHT`` A -1 indicates that a class-specific default should be used for the height. - ``wx.SIZE_USE_EXISTING`` Existing dimensions should be used if -1 values are supplied. - ``wx.SIZE_ALLOW_MINUS_ONE`` Allow dimensions of -1 and less to be interpreted as real dimensions, not default values. - ``wx.SIZE_FORCE`` Normally, if the position and the size of the window are already the same as the - parameters of this function, nothing is done. but with this flag a window resize may - be forced even in this case (supported in wx 2.6.2 and later and only implemented - for MSW and ignored elsewhere currently) - =================================== ====================================== - - :note: Overridden from :class:`PyControl`. - """ - - parent_size = self.GetParent().GetClientSize() - if x + width > parent_size.x: - width = max(0, parent_size.x - x) - if y + height > parent_size.y: - height = max(0, parent_size.y - y) - - wx.PyControl.DoSetSize(self, x, y, width, height, sizeFlags) - - - def OnIdle(self, event): - """ - Handles the ``wx.EVT_IDLE`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`IdleEvent` event to be processed. - """ - - self.DoIdleUpdate() - event.Skip() - - - def DoGetBestSize(self): - """ - Gets the size which best suits the window: for a control, it would be the - minimal size which doesn't truncate the control, for a panel - the same - size as it would have after a call to `Fit()`. - - :note: Overridden from :class:`PyControl`. - """ - return self._absolute_min_size - - - def OnPaint(self, event): - """ - Handles the ``wx.EVT_PAINT`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`PaintEvent` event to be processed. - """ - dc = wx.AutoBufferedPaintDC(self) - cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize()) - - horizontal = True - if self._agwStyle & AUI_TB_VERTICAL: - horizontal = False - - if self._agwStyle & AUI_TB_PLAIN_BACKGROUND: - self._art.DrawPlainBackground(dc, self, cli_rect) - else: - self._art.DrawBackground(dc, self, cli_rect, horizontal) - - gripper_size = self._art.GetElementSize(AUI_TBART_GRIPPER_SIZE) - dropdown_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE) - - # paint the gripper - if self._agwStyle & AUI_TB_GRIPPER and gripper_size > 0 and self._gripper_sizer_item: - gripper_rect = wx.Rect(*self._gripper_sizer_item.GetRect()) - if horizontal: - gripper_rect.width = gripper_size - else: - gripper_rect.height = gripper_size - - self._art.DrawGripper(dc, self, gripper_rect) - - # calculated how far we can draw items - if horizontal: - last_extent = cli_rect.width - else: - last_extent = cli_rect.height - - if self._overflow_visible: - last_extent -= dropdown_size - - # paint each individual tool - for item in self._items: - - if not item.sizer_item: - continue - - item_rect = wx.Rect(*item.sizer_item.GetRect()) - - if (horizontal and item_rect.x + item_rect.width >= last_extent) or \ - (not horizontal and item_rect.y + item_rect.height >= last_extent): - - break - - if item.kind == ITEM_SEPARATOR: - # draw a separator - self._art.DrawSeparator(dc, self, item_rect) - - elif item.kind == ITEM_LABEL: - # draw a text label only - self._art.DrawLabel(dc, self, item, item_rect) - - elif item.kind == ITEM_NORMAL: - # draw a regular button or dropdown button - if not item.dropdown: - self._art.DrawButton(dc, self, item, item_rect) - else: - self._art.DrawDropDownButton(dc, self, item, item_rect) - - elif item.kind == ITEM_CHECK: - # draw a regular toggle button or a dropdown one - if not item.dropdown: - self._art.DrawButton(dc, self, item, item_rect) - else: - self._art.DrawDropDownButton(dc, self, item, item_rect) - - elif item.kind == ITEM_RADIO: - # draw a toggle button - self._art.DrawButton(dc, self, item, item_rect) - - elif item.kind == ITEM_CONTROL: - # draw the control's label - self._art.DrawControlLabel(dc, self, item, item_rect) - - # fire a signal to see if the item wants to be custom-rendered - self.OnCustomRender(dc, item, item_rect) - - # paint the overflow button - if dropdown_size > 0 and self._overflow_sizer_item: - dropdown_rect = self.GetOverflowRect() - self._art.DrawOverflowButton(dc, self, dropdown_rect, self._overflow_state) - - - def OnEraseBackground(self, event): - """ - Handles the ``wx.EVT_ERASE_BACKGROUND`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`EraseEvent` event to be processed. - - :note: This is intentionally empty, to reduce flicker. - """ - - pass - - - def OnLeftDown(self, event): - """ - Handles the ``wx.EVT_LEFT_DOWN`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize()) - self.StopPreviewTimer() - - if self._gripper_sizer_item: - - gripper_rect = wx.Rect(*self._gripper_sizer_item.GetRect()) - if gripper_rect.Contains(event.GetPosition()): - - # find aui manager - manager = self.GetAuiManager() - if not manager: - return - - x_drag_offset = event.GetX() - gripper_rect.GetX() - y_drag_offset = event.GetY() - gripper_rect.GetY() - - clientPt = wx.Point(*event.GetPosition()) - screenPt = self.ClientToScreen(clientPt) - managedWindow = manager.GetManagedWindow() - managerClientPt = managedWindow.ScreenToClient(screenPt) - - # gripper was clicked - manager.OnGripperClicked(self, managerClientPt, wx.Point(x_drag_offset, y_drag_offset)) - return - - if self._overflow_sizer_item: - overflow_rect = self.GetOverflowRect() - - if self._art and self._overflow_visible and overflow_rect.Contains(event.GetPosition()): - - e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, -1) - e.SetEventObject(self) - e.SetToolId(-1) - e.SetClickPoint(event.GetPosition()) - processed = self.ProcessEvent(e) - - if processed: - self.DoIdleUpdate() - else: - overflow_items = [] - - # add custom overflow prepend items, if any - count = len(self._custom_overflow_prepend) - for i in xrange(count): - overflow_items.append(self._custom_overflow_prepend[i]) - - # only show items that don't fit in the dropdown - count = len(self._items) - for i in xrange(count): - - if not self.GetToolFitsByIndex(i): - overflow_items.append(self._items[i]) - - # add custom overflow append items, if any - count = len(self._custom_overflow_append) - for i in xrange(count): - overflow_items.append(self._custom_overflow_append[i]) - - res = self._art.ShowDropDown(self, overflow_items) - self._overflow_state = 0 - self.Refresh(False) - if res != -1: - e = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, res) - e.SetEventObject(self) - if not self.GetParent().ProcessEvent(e): - tool = self.FindTool(res) - if tool: - state = (tool.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0] - self.ToggleTool(res, not state) - - return - - self._dragging = False - self._action_pos = wx.Point(*event.GetPosition()) - self._action_item = self.FindToolForPosition(*event.GetPosition()) - - if self._action_item: - - if self._action_item.state & AUI_BUTTON_STATE_DISABLED: - - self._action_pos = wx.Point(-1, -1) - self._action_item = None - return - - self.SetPressedItem(self._action_item) - - # fire the tool dropdown event - e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, self._action_item.id) - e.SetEventObject(self) - e.SetToolId(self._action_item.id) - e.SetDropDownClicked(False) - - mouse_x, mouse_y = event.GetX(), event.GetY() - rect = wx.Rect(*self._action_item.sizer_item.GetRect()) - - if self._action_item.dropdown: - if (self._action_item.orientation == AUI_TBTOOL_HORIZONTAL and \ - mouse_x >= (rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1) and \ - mouse_x < (rect.x+rect.width)) or \ - (self._action_item.orientation != AUI_TBTOOL_HORIZONTAL and \ - mouse_y >= (rect.y+rect.height-BUTTON_DROPDOWN_WIDTH-1) and \ - mouse_y < (rect.y+rect.height)): - - e.SetDropDownClicked(True) - - e.SetClickPoint(event.GetPosition()) - e.SetItemRect(rect) - self.ProcessEvent(e) - self.DoIdleUpdate() - - - def OnLeftUp(self, event): - """ - Handles the ``wx.EVT_LEFT_UP`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - self.SetPressedItem(None) - - hit_item = self.FindToolForPosition(*event.GetPosition()) - - if hit_item and not hit_item.state & AUI_BUTTON_STATE_DISABLED: - self.SetHoverItem(hit_item) - - if self._dragging: - # reset drag and drop member variables - self._dragging = False - self._action_pos = wx.Point(-1, -1) - self._action_item = None - - else: - - if self._action_item and hit_item == self._action_item: - self.SetToolTipString("") - - if hit_item.kind in [ITEM_CHECK, ITEM_RADIO]: - toggle = not (self._action_item.state & AUI_BUTTON_STATE_CHECKED) - self.ToggleTool(self._action_item.id, toggle) - - # repaint immediately - self.Refresh(False) - self.Update() - - e = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, self._action_item.id) - e.SetEventObject(self) - e.SetInt(toggle) - self._action_pos = wx.Point(-1, -1) - self._action_item = None - - self.ProcessEvent(e) - self.DoIdleUpdate() - - else: - - if self._action_item.id == ID_RESTORE_FRAME: - # find aui manager - manager = self.GetAuiManager() - - if not manager: - return - - if self._action_item.target: - pane = manager.GetPane(self._action_item.target) - else: - pane = manager.GetPane(self) - - e = framemanager.AuiManagerEvent(framemanager.wxEVT_AUI_PANE_MIN_RESTORE) - - e.SetManager(manager) - e.SetPane(pane) - - manager.ProcessEvent(e) - self.DoIdleUpdate() - - else: - - e = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, self._action_item.id) - e.SetEventObject(self) - self.ProcessEvent(e) - self.DoIdleUpdate() - - # reset drag and drop member variables - self._dragging = False - self._action_pos = wx.Point(-1, -1) - self._action_item = None - - - def OnRightDown(self, event): - """ - Handles the ``wx.EVT_RIGHT_DOWN`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize()) - - if self._gripper_sizer_item: - gripper_rect = self._gripper_sizer_item.GetRect() - if gripper_rect.Contains(event.GetPosition()): - return - - if self._overflow_sizer_item: - - dropdown_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE) - if dropdown_size > 0 and event.GetX() > cli_rect.width - dropdown_size and \ - event.GetY() >= 0 and event.GetY() < cli_rect.height and self._art: - return - - self._action_pos = wx.Point(*event.GetPosition()) - self._action_item = self.FindToolForPosition(*event.GetPosition()) - - if self._action_item: - if self._action_item.state & AUI_BUTTON_STATE_DISABLED: - - self._action_pos = wx.Point(-1, -1) - self._action_item = None - return - - - def OnRightUp(self, event): - """ - Handles the ``wx.EVT_RIGHT_UP`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - hit_item = self.FindToolForPosition(*event.GetPosition()) - - if self._action_item and hit_item == self._action_item: - - e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, self._action_item.id) - e.SetEventObject(self) - e.SetToolId(self._action_item.id) - e.SetClickPoint(self._action_pos) - self.ProcessEvent(e) - self.DoIdleUpdate() - - else: - - # right-clicked on the invalid area of the toolbar - e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, -1) - e.SetEventObject(self) - e.SetToolId(-1) - e.SetClickPoint(self._action_pos) - self.ProcessEvent(e) - self.DoIdleUpdate() - - # reset member variables - self._action_pos = wx.Point(-1, -1) - self._action_item = None - - - def OnMiddleDown(self, event): - """ - Handles the ``wx.EVT_MIDDLE_DOWN`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize()) - - if self._gripper_sizer_item: - - gripper_rect = self._gripper_sizer_item.GetRect() - if gripper_rect.Contains(event.GetPosition()): - return - - if self._overflow_sizer_item: - - dropdown_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE) - if dropdown_size > 0 and event.GetX() > cli_rect.width - dropdown_size and \ - event.GetY() >= 0 and event.GetY() < cli_rect.height and self._art: - return - - self._action_pos = wx.Point(*event.GetPosition()) - self._action_item = self.FindToolForPosition(*event.GetPosition()) - - if self._action_item: - if self._action_item.state & AUI_BUTTON_STATE_DISABLED: - - self._action_pos = wx.Point(-1, -1) - self._action_item = None - return - - - def OnMiddleUp(self, event): - """ - Handles the ``wx.EVT_MIDDLE_UP`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - hit_item = self.FindToolForPosition(*event.GetPosition()) - - if self._action_item and hit_item == self._action_item: - if hit_item.kind == ITEM_NORMAL: - - e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, self._action_item.id) - e.SetEventObject(self) - e.SetToolId(self._action_item.id) - e.SetClickPoint(self._action_pos) - self.ProcessEvent(e) - self.DoIdleUpdate() - - # reset member variables - self._action_pos = wx.Point(-1, -1) - self._action_item = None - - - def OnMotion(self, event): - """ - Handles the ``wx.EVT_MOTION`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - # start a drag event - if not self._dragging and self._action_item != None and self._action_pos != wx.Point(-1, -1) and \ - abs(event.GetX() - self._action_pos.x) + abs(event.GetY() - self._action_pos.y) > 5: - - self.SetToolTipString("") - self._dragging = True - - e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, self.GetId()) - e.SetEventObject(self) - e.SetToolId(self._action_item.id) - self.ProcessEvent(e) - self.DoIdleUpdate() - return - - hit_item = self.FindToolForPosition(*event.GetPosition()) - - if hit_item: - if not hit_item.state & AUI_BUTTON_STATE_DISABLED: - self.SetHoverItem(hit_item) - else: - self.SetHoverItem(None) - - else: - # no hit item, remove any hit item - self.SetHoverItem(hit_item) - - # figure out tooltips - packing_hit_item = self.FindToolForPositionWithPacking(*event.GetPosition()) - - if packing_hit_item: - - if packing_hit_item != self._tip_item: - self._tip_item = packing_hit_item - - if packing_hit_item.short_help != "": - self.StartPreviewTimer() - self.SetToolTipString(packing_hit_item.short_help) - else: - self.SetToolTipString("") - self.StopPreviewTimer() - - else: - - self.SetToolTipString("") - self._tip_item = None - self.StopPreviewTimer() - - # if we've pressed down an item and we're hovering - # over it, make sure it's state is set to pressed - if self._action_item: - - if self._action_item == hit_item: - self.SetPressedItem(self._action_item) - else: - self.SetPressedItem(None) - - # figure out the dropdown button state (are we hovering or pressing it?) - self.RefreshOverflowState() - - - def OnLeaveWindow(self, event): - """ - Handles the ``wx.EVT_LEAVE_WINDOW`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - self.RefreshOverflowState() - self.SetHoverItem(None) - self.SetPressedItem(None) - - self._tip_item = None - self.StopPreviewTimer() - - - def OnSetCursor(self, event): - """ - Handles the ``wx.EVT_SET_CURSOR`` event for :class:`AuiToolBar`. - - :param `event`: a :class:`SetCursorEvent` event to be processed. - """ - - cursor = wx.NullCursor - - if self._gripper_sizer_item: - - gripper_rect = self._gripper_sizer_item.GetRect() - if gripper_rect.Contains((event.GetX(), event.GetY())): - cursor = wx.StockCursor(wx.CURSOR_SIZING) - - event.SetCursor(cursor) - - - def OnCustomRender(self, dc, item, rect): - """ - Handles custom render for single :class:`AuiToolBar` items. - - :param `dc`: a :class:`DC` device context; - :param `item`: an instance of :class:`AuiToolBarItem`; - :param Rect `rect`: the toolbar item rect. - - :note: This method must be overridden to provide custom rendering of items. - """ - - pass - - - def IsPaneMinimized(self): - """ Returns whether this :class:`AuiToolBar` contains a minimized pane tool. """ - - manager = self.GetAuiManager() - if not manager: - return False - - if manager.GetAGWFlags() & AUI_MGR_PREVIEW_MINIMIZED_PANES == 0: - # No previews here - return False - - self_name = manager.GetPane(self).name - - if not self_name.endswith("_min"): - # Wrong tool name - return False - - return self_name[0:-4] - - - def StartPreviewTimer(self): - """ Starts a timer in :class:`~lib.agw.aui.framemanager.AuiManager` to slide-in/slide-out the minimized pane. """ - - self_name = self.IsPaneMinimized() - if not self_name: - return - - manager = self.GetAuiManager() - manager.StartPreviewTimer(self) - - - def StopPreviewTimer(self): - """ Stops a timer in :class:`~lib.agw.aui.framemanager.AuiManager` to slide-in/slide-out the minimized pane. """ - - self_name = self.IsPaneMinimized() - if not self_name: - return - - manager = self.GetAuiManager() - manager.StopPreviewTimer() - diff --git a/enaml/wx/wx_upstream/aui/auibook.py b/enaml/wx/wx_upstream/aui/auibook.py deleted file mode 100644 index a5d4d0728..000000000 --- a/enaml/wx/wx_upstream/aui/auibook.py +++ /dev/null @@ -1,5922 +0,0 @@ -""" -`auibook.py` contains a notebook control which implements many features common in -applications with dockable panes. Specifically, :class:`AuiNotebook` implements functionality -which allows the user to rearrange tab order via drag-and-drop, split the tab window -into many different splitter configurations, and toggle through different themes to -customize the control's look and feel. - -An effort has been made to try to maintain an API as similar to that of :class:`Notebook`. - -The default theme that is used is :class:`~lib.agw.aui.tabart.AuiDefaultTabArt`, which provides a modern, glossy -look and feel. The theme can be changed by calling :meth:`AuiNotebook.SetArtProvider() `. -""" - -__author__ = "Andrea Gavana " -__date__ = "31 March 2009" - - -import wx -import types -import datetime - -from wx.lib.expando import ExpandoTextCtrl - -import framemanager -import tabart as TA - -from aui_utilities import LightColour, MakeDisabledBitmap, TabDragImage -from aui_utilities import TakeScreenShot, RescaleScreenShot - -from aui_constants import * - -# AuiNotebook events -wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_BUTTON = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_END_DRAG = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_TAB_DCLICK = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_DOWN = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_UP = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_DOWN = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_UP = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK = wx.NewEventType() - -# Define a new event for a drag cancelled -wxEVT_COMMAND_AUINOTEBOOK_CANCEL_DRAG = wx.NewEventType() - -# Define events for editing a tab label -wxEVT_COMMAND_AUINOTEBOOK_BEGIN_LABEL_EDIT = wx.NewEventType() -wxEVT_COMMAND_AUINOTEBOOK_END_LABEL_EDIT = wx.NewEventType() - -# Create event binders -EVT_AUINOTEBOOK_PAGE_CLOSE = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 1) -""" A tab in `AuiNotebook` is being closed. Can be vetoed by calling `Veto()`. """ -EVT_AUINOTEBOOK_PAGE_CLOSED = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 1) -""" A tab in `AuiNotebook` has been closed. """ -EVT_AUINOTEBOOK_PAGE_CHANGED = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 1) -""" The page selection was changed. """ -EVT_AUINOTEBOOK_PAGE_CHANGING = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 1) -""" The page selection is being changed. """ -EVT_AUINOTEBOOK_BUTTON = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 1) -""" The user clicked on a button in the `AuiNotebook` tab area. """ -EVT_AUINOTEBOOK_BEGIN_DRAG = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 1) -""" A drag-and-drop operation on a notebook tab has started. """ -EVT_AUINOTEBOOK_END_DRAG = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 1) -""" A drag-and-drop operation on a notebook tab has finished. """ -EVT_AUINOTEBOOK_DRAG_MOTION = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 1) -""" A drag-and-drop operation on a notebook tab is ongoing. """ -EVT_AUINOTEBOOK_ALLOW_DND = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 1) -""" Fires an event asking if it is OK to drag and drop a tab. """ -EVT_AUINOTEBOOK_DRAG_DONE = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 1) -""" A drag-and-drop operation on a notebook tab has finished. """ -EVT_AUINOTEBOOK_TAB_MIDDLE_DOWN = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 1) -""" The user clicked with the middle mouse button on a tab. """ -EVT_AUINOTEBOOK_TAB_MIDDLE_UP = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 1) -""" The user clicked with the middle mouse button on a tab. """ -EVT_AUINOTEBOOK_TAB_RIGHT_DOWN = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 1) -""" The user clicked with the right mouse button on a tab. """ -EVT_AUINOTEBOOK_TAB_RIGHT_UP = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 1) -""" The user clicked with the right mouse button on a tab. """ -EVT_AUINOTEBOOK_BG_MIDDLE_DOWN = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_DOWN, 1) -""" The user middle-clicked in the tab area but not over a tab or a button. """ -EVT_AUINOTEBOOK_BG_MIDDLE_UP = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_UP, 1) -""" The user middle-clicked in the tab area but not over a tab or a button. """ -EVT_AUINOTEBOOK_BG_RIGHT_DOWN = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_DOWN, 1) -""" The user right-clicked in the tab area but not over a tab or a button. """ -EVT_AUINOTEBOOK_BG_RIGHT_UP = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_UP, 1) -""" The user right-clicked in the tab area but not over a tab or a button. """ -EVT_AUINOTEBOOK_BG_DCLICK = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 1) -""" The user left-clicked on the tab area not occupied by `AuiNotebook` tabs. """ -EVT_AUINOTEBOOK_CANCEL_DRAG = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_CANCEL_DRAG, 1) -""" A drag and drop operation has been cancelled. """ -EVT_AUINOTEBOOK_TAB_DCLICK = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_TAB_DCLICK, 1) -""" The user double-clicked with the left mouse button on a tab. """ -EVT_AUINOTEBOOK_BEGIN_LABEL_EDIT = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_LABEL_EDIT, 1) -""" The user double-clicked with the left mouse button on a tab which text is editable. """ -EVT_AUINOTEBOOK_END_LABEL_EDIT = wx.PyEventBinder(wxEVT_COMMAND_AUINOTEBOOK_END_LABEL_EDIT, 1) -""" The user finished editing a tab label. """ - - -# ----------------------------------------------------------------------------- -# Auxiliary class: TabTextCtrl -# This is the temporary ExpandoTextCtrl created when you edit the text of a tab -# ----------------------------------------------------------------------------- - -class TabTextCtrl(ExpandoTextCtrl): - """ Control used for in-place edit. """ - - def __init__(self, owner, tab, page_index): - """ - Default class constructor. - For internal use: do not call it in your code! - - :param `owner`: the :class:`AuiNotebook` owning the tab; - :param `tab`: the actual :class:`AuiTabCtrl` tab; - :param integer `page_index`: the :class:`AuiTabContainer` page index for the tab. - """ - - self._owner = owner - self._tabEdited = tab - self._pageIndex = page_index - self._startValue = tab.caption - self._finished = False - self._aboutToFinish = False - self._currentValue = self._startValue - - x, y, w, h = self._tabEdited.rect - - wnd = self._tabEdited.control - if wnd: - x += wnd.GetSize()[0] + 2 - h = 0 - - image_h = 0 - image_w = 0 - - image = tab.bitmap - - if image.IsOk(): - image_w, image_h = image.GetWidth(), image.GetHeight() - image_w += 6 - - dc = wx.ClientDC(self._owner) - h = max(image_h, dc.GetMultiLineTextExtent(tab.caption)[1]) - h = h + 2 - - # FIXME: what are all these hardcoded 4, 8 and 11s really? - x += image_w - w -= image_w + 4 - - y = (self._tabEdited.rect.height - h)/2 + 1 - - expandoStyle = wx.WANTS_CHARS - if wx.Platform in ["__WXGTK__", "__WXMAC__"]: - expandoStyle |= wx.SIMPLE_BORDER - xSize, ySize = w + 2, h - else: - expandoStyle |= wx.SUNKEN_BORDER - xSize, ySize = w + 2, h+2 - - ExpandoTextCtrl.__init__(self, self._owner, wx.ID_ANY, self._startValue, - wx.Point(x, y), wx.Size(xSize, ySize), - expandoStyle) - - if wx.Platform == "__WXMAC__": - self.SetFont(owner.GetFont()) - bs = self.GetBestSize() - self.SetSize((-1, bs.height)) - - self.Bind(wx.EVT_CHAR, self.OnChar) - self.Bind(wx.EVT_KEY_UP, self.OnKeyUp) - self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) - - - def AcceptChanges(self): - """ Accepts/refuses the changes made by the user. """ - - value = self.GetValue() - notebook = self._owner.GetParent() - - if value == self._startValue: - # nothing changed, always accept - # when an item remains unchanged, the owner - # needs to be notified that the user decided - # not to change the tree item label, and that - # the edit has been cancelled - notebook.OnRenameCancelled(self._pageIndex) - return True - - if not notebook.OnRenameAccept(self._pageIndex, value): - # vetoed by the user - return False - - # accepted, do rename the item - notebook.SetPageText(self._pageIndex, value) - - return True - - - def Finish(self): - """ Finish editing. """ - - if not self._finished: - - notebook = self._owner.GetParent() - - self._finished = True - self._owner.SetFocus() - notebook.ResetTextControl() - - - def OnChar(self, event): - """ - Handles the ``wx.EVT_CHAR`` event for :class:`TabTextCtrl`. - - :param `event`: a :class:`KeyEvent` event to be processed. - """ - - keycode = event.GetKeyCode() - shiftDown = event.ShiftDown() - - if keycode == wx.WXK_RETURN: - if shiftDown and self._tabEdited.IsMultiline(): - event.Skip() - else: - self._aboutToFinish = True - self.SetValue(self._currentValue) - # Notify the owner about the changes - self.AcceptChanges() - # Even if vetoed, close the control (consistent with MSW) - wx.CallAfter(self.Finish) - - elif keycode == wx.WXK_ESCAPE: - self.StopEditing() - - else: - event.Skip() - - - def OnKeyUp(self, event): - """ - Handles the ``wx.EVT_KEY_UP`` event for :class:`TabTextCtrl`. - - :param `event`: a :class:`KeyEvent` event to be processed. - """ - - if not self._finished: - - # auto-grow the textctrl: - mySize = self.GetSize() - - dc = wx.ClientDC(self) - sx, sy, dummy = dc.GetMultiLineTextExtent(self.GetValue() + "M") - - self.SetSize((sx, -1)) - self._currentValue = self.GetValue() - - event.Skip() - - - def OnKillFocus(self, event): - """ - Handles the ``wx.EVT_KILL_FOCUS`` event for :class:`TabTextCtrl`. - - :param `event`: a :class:`FocusEvent` event to be processed. - """ - - if not self._finished and not self._aboutToFinish: - - # We must finish regardless of success, otherwise we'll get - # focus problems: - if not self.AcceptChanges(): - self._owner.GetParent().OnRenameCancelled(self._pageIndex) - - # We must let the native text control handle focus, too, otherwise - # it could have problems with the cursor (e.g., in wxGTK). - event.Skip() - wx.CallAfter(self._owner.GetParent().ResetTextControl) - - - def StopEditing(self): - """ Suddenly stops the editing. """ - - self._owner.GetParent().OnRenameCancelled(self._pageIndex) - self.Finish() - - - def item(self): - """ Returns the item currently edited. """ - - return self._tabEdited - - -# ---------------------------------------------------------------------- - -class AuiNotebookPage(object): - """ - A simple class which holds information about tab captions, bitmaps and - colours. - """ - - def __init__(self): - """ - Default class constructor. - Used internally, do not call it in your code! - """ - - self.window = None # page's associated window - self.caption = "" # caption displayed on the tab - self.bitmap = wx.NullBitmap # tab's bitmap - self.dis_bitmap = wx.NullBitmap # tab's disabled bitmap - self.rect = wx.Rect() # tab's hit rectangle - self.active = False # True if the page is currently active - self.enabled = True # True if the page is currently enabled - self.hasCloseButton = True # True if the page has a close button using the style - # AUI_NB_CLOSE_ON_ALL_TABS - self.control = None # A control can now be inside a tab - self.renamable = False # If True, a tab can be renamed by a left double-click - - self.text_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNTEXT) - - self.access_time = datetime.datetime.now() # Last time this page was selected - - - def IsMultiline(self): - """ Returns whether the tab contains multiline text. """ - - return "\n" in self.caption - - -# ---------------------------------------------------------------------- - -class AuiTabContainerButton(object): - """ - A simple class which holds information about tab buttons and their state. - """ - - def __init__(self): - """ - Default class constructor. - Used internally, do not call it in your code! - """ - - self.id = -1 # button's id - self.cur_state = AUI_BUTTON_STATE_NORMAL # current state (normal, hover, pressed, etc.) - self.location = wx.LEFT # buttons location (wxLEFT, wxRIGHT, or wxCENTER) - self.bitmap = wx.NullBitmap # button's hover bitmap - self.dis_bitmap = wx.NullBitmap # button's disabled bitmap - self.rect = wx.Rect() # button's hit rectangle - - -# ---------------------------------------------------------------------- - -class CommandNotebookEvent(wx.PyCommandEvent): - """ A specialized command event class for events sent by :class:`AuiNotebook` . """ - - def __init__(self, command_type=None, win_id=0): - """ - Default class constructor. - - :param `command_type`: the event kind or an instance of :class:`PyCommandEvent`. - :param integer `win_id`: the window identification number. - """ - - if type(command_type) == types.IntType: - wx.PyCommandEvent.__init__(self, command_type, win_id) - else: - wx.PyCommandEvent.__init__(self, command_type.GetEventType(), command_type.GetId()) - - self.old_selection = -1 - self.selection = -1 - self.drag_source = None - self.dispatched = 0 - self.label = "" - self.editCancelled = False - self.page = None - - - def SetSelection(self, s): - """ - Sets the selection member variable. - - :param integer `s`: the new selection. - """ - - self.selection = s - self._commandInt = s - - - def GetSelection(self): - """ Returns the currently selected page, or -1 if none was selected. """ - - return self.selection - - - def SetOldSelection(self, s): - """ - Sets the id of the page selected before the change. - - :param integer `s`: the old selection. - """ - - self.old_selection = s - - - def GetOldSelection(self): - """ - Returns the page that was selected before the change, or -1 if none was - selected. - """ - - return self.old_selection - - - def SetDragSource(self, s): - """ - Sets the drag and drop source. - - :param `s`: the drag source. - """ - - self.drag_source = s - - - def GetDragSource(self): - """ Returns the drag and drop source. """ - - return self.drag_source - - - def SetDispatched(self, b): - """ - Sets the event as dispatched (used for automatic :class:`AuiNotebook` ). - - :param `b`: whether the event was dispatched or not. - """ - - self.dispatched = b - - - def GetDispatched(self): - """ Returns whether the event was dispatched (used for automatic :class:`AuiNotebook` ). """ - - return self.dispatched - - - def IsEditCancelled(self): - """ Returns the edit cancel flag (for ``EVT_AUINOTEBOOK_BEGIN`` | ``END_LABEL_EDIT`` only).""" - - return self.editCancelled - - - def SetEditCanceled(self, editCancelled): - """ - Sets the edit cancel flag (for ``EVT_AUINOTEBOOK_BEGIN`` | ``END_LABEL_EDIT`` only). - - :param bool `editCancelled`: whether the editing action has been cancelled or not. - """ - - self.editCancelled = editCancelled - - - def GetLabel(self): - """Returns the label-itemtext (for ``EVT_AUINOTEBOOK_BEGIN`` | ``END_LABEL_EDIT`` only).""" - - return self.label - - - def SetLabel(self, label): - """ - Sets the label. Useful only for ``EVT_AUINOTEBOOK_END_LABEL_EDIT``. - - :param string `label`: the new label. - """ - - self.label = label - - - Page = property(lambda self: self.page, - lambda self, page: setattr(self, 'page', page)) - Selection = property(lambda self: self.GetSelection(), lambda self, sel: self.SetSelection(sel)) - -# ---------------------------------------------------------------------- - -class AuiNotebookEvent(CommandNotebookEvent): - """ A specialized command event class for events sent by :class:`AuiNotebook`. """ - - def __init__(self, command_type=None, win_id=0): - """ - Default class constructor. - - :param `command_type`: the event kind or an instance of :class:`PyCommandEvent`. - :param integer `win_id`: the window identification number. - """ - - CommandNotebookEvent.__init__(self, command_type, win_id) - - if type(command_type) == types.IntType: - self.notify = wx.NotifyEvent(command_type, win_id) - else: - self.notify = wx.NotifyEvent(command_type.GetEventType(), command_type.GetId()) - - - def GetNotifyEvent(self): - """ Returns the actual :class:`NotifyEvent`. """ - - return self.notify - - - def IsAllowed(self): - """ Returns whether the event is allowed or not. """ - - return self.notify.IsAllowed() - - - def Veto(self): - """ - Prevents the change announced by this event from happening. - - It is in general a good idea to notify the user about the reasons for - vetoing the change because otherwise the applications behaviour (which - just refuses to do what the user wants) might be quite surprising. - """ - - self.notify.Veto() - - - def Allow(self): - """ - This is the opposite of :meth:`Veto`: it explicitly allows the event to be - processed. For most events it is not necessary to call this method as the - events are allowed anyhow but some are forbidden by default (this will - be mentioned in the corresponding event description). - """ - - self.notify.Allow() - - -# ---------------------------------------------------------------------------- # -# Class TabNavigatorProps -# ---------------------------------------------------------------------------- # - -class TabNavigatorProps(object): - """ - Data storage class for managing and providing access to :class:`TabNavigatorWindow` properties. - """ - - def __init__(self): - """ Default class constructor. """ - - super(TabNavigatorProps, self).__init__() - - # Attributes - self._icon = wx.NullBitmap - self._font = wx.NullFont - self._minsize = wx.DefaultSize - - # Accessors - Icon = property(lambda self: self._icon, - lambda self, icon: setattr(self, '_icon', icon), - doc='Sets/Gets the icon for the L{TabNavigatorWindow}, an instance of :class:`Bitmap`.') - Font = property(lambda self: self._font, - lambda self, font: setattr(self, '_font', font), - doc='Sets/Gets the font for the L{TabNavigatorWindow}, an instance of :class:`Font`.') - MinSize = property(lambda self: self._minsize, - lambda self, size: setattr(self, '_minsize', size), - doc='Sets/Gets the minimum size for the L{TabNavigatorWindow}, an instance of :class:`Size`.') - -# ---------------------------------------------------------------------------- # -# Class TabNavigatorWindow -# ---------------------------------------------------------------------------- # - -class TabNavigatorWindow(wx.Dialog): - """ - This class is used to create a modal dialog that enables "Smart Tabbing", - similar to what you would get by hitting ``Alt`` + ``Tab`` on Windows. - """ - - def __init__(self, parent, props): - """ - Default class constructor. Used internally. - - :param `parent`: the :class:`TabNavigatorWindow` parent; - :param `props`: the :class:`TabNavigatorProps` object. - """ - - wx.Dialog.__init__(self, parent, wx.ID_ANY, "", size=props.MinSize, style=0) - - self._selectedItem = -1 - self._indexMap = [] - self._props = props - - if not self._props.Icon.IsOk(): - self._props.Icon = Mondrian.GetBitmap() - - if props.Icon.GetSize() != (16, 16): - img = self._props.Icon.ConvertToImage() - img.Rescale(16, 16, wx.IMAGE_QUALITY_HIGH) - self._props.Icon = wx.BitmapFromImage(img) - - if self._props.Font.IsOk(): - self.Font = self._props.Font - - sz = wx.BoxSizer(wx.VERTICAL) - - self._listBox = wx.ListBox(self, wx.ID_ANY, - wx.DefaultPosition, - wx.Size(200, 150), [], - wx.LB_SINGLE | wx.NO_BORDER) - - mem_dc = wx.MemoryDC() - mem_dc.SelectObject(wx.EmptyBitmap(1,1)) - font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) - font.SetWeight(wx.BOLD) - mem_dc.SetFont(font) - - panelHeight = mem_dc.GetCharHeight() - panelHeight += 4 # Place a spacer of 2 pixels - - # Out signpost bitmap is 24 pixels - if panelHeight < 24: - panelHeight = 24 - - self._panel = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, - wx.Size(-1, panelHeight)) - - sz.Add(self._panel, 0, wx.EXPAND) - sz.Add(self._listBox, 1, wx.EXPAND) - - self.SetSizer(sz) - - # Connect events to the list box - self._listBox.Bind(wx.EVT_KEY_UP, self.OnKeyUp) - self._listBox.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey) - self._listBox.Bind(wx.EVT_LISTBOX_DCLICK, self.OnItemSelected) - - # Connect paint event to the panel - self._panel.Bind(wx.EVT_PAINT, self.OnPanelPaint) - self._panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnPanelEraseBg) - - self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)) - self._listBox.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)) - self.PopulateListControl(parent) - - self.SetInitialSize(props.MinSize) - self.Centre() - - # Set focus on the list box to avoid having to click on it to change - # the tab selection under GTK. - self._listBox.SetFocus() - - - def OnKeyUp(self, event): - """ - Handles the ``wx.EVT_KEY_UP`` for the :class:`TabNavigatorWindow`. - - :param `event`: a :class:`KeyEvent` event to be processed. - """ - - if event.GetKeyCode() == wx.WXK_CONTROL: - self.CloseDialog() - - - def OnNavigationKey(self, event): - """ - Handles the ``wx.EVT_NAVIGATION_KEY`` for the :class:`TabNavigatorWindow`. - - :param `event`: a :class:`NavigationKeyEvent` event to be processed. - """ - - selected = self._listBox.GetSelection() - bk = self.GetParent() - maxItems = bk.GetPageCount() - - if event.GetDirection(): - - # Select next page - if selected == maxItems - 1: - itemToSelect = 0 - else: - itemToSelect = selected + 1 - - else: - - # Previous page - if selected == 0: - itemToSelect = maxItems - 1 - else: - itemToSelect = selected - 1 - - self._listBox.SetSelection(itemToSelect) - - - def PopulateListControl(self, book): - """ - Populates the :class:`TabNavigatorWindow` listbox with a list of tabs. - - :param `book`: the actual :class:`AuiNotebook`. - """ - # Index of currently selected page - selection = book.GetSelection() - # Total number of pages - count = book.GetPageCount() - # List of (index, AuiNotebookPage) - pages = list(enumerate(book.GetTabContainer().GetPages())) - if book.GetAGWWindowStyleFlag() & AUI_NB_ORDER_BY_ACCESS: - # Sort pages using last access time. Most recently used is the - # first in line - pages.sort( - key = lambda element: element[1].access_time, - reverse = True - ) - else: - # Manually add the current selection as first item - # Remaining ones are added in the next loop - del pages[selection] - self._listBox.Append(book.GetPageText(selection)) - self._indexMap.append(selection) - - for (index, page) in pages: - self._listBox.Append(book.GetPageText(index)) - self._indexMap.append(index) - - # Select the next entry after the current selection - self._listBox.SetSelection(0) - dummy = wx.NavigationKeyEvent() - dummy.SetDirection(True) - self.OnNavigationKey(dummy) - - - def OnItemSelected(self, event): - """ - Handles the ``wx.EVT_LISTBOX_DCLICK`` event for the :class:`ListBox` inside :class:`TabNavigatorWindow`. - - :param `event`: a :class:`ListEvent` event to be processed. - """ - - self.CloseDialog() - - - def CloseDialog(self): - """ Closes the :class:`TabNavigatorWindow` dialog, setting selection in :class:`AuiNotebook`. """ - - bk = self.GetParent() - self._selectedItem = self._listBox.GetSelection() - self.EndModal(wx.ID_OK) - - - def GetSelectedPage(self): - """ Gets the page index that was selected when the dialog was closed. """ - - return self._indexMap[self._selectedItem] - - - def OnPanelPaint(self, event): - """ - Handles the ``wx.EVT_PAINT`` event for :class:`TabNavigatorWindow` top panel. - - :param `event`: a :class:`PaintEvent` event to be processed. - """ - - dc = wx.PaintDC(self._panel) - rect = self._panel.GetClientRect() - - bmp = wx.EmptyBitmap(rect.width, rect.height) - - mem_dc = wx.MemoryDC() - mem_dc.SelectObject(bmp) - - endColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW) - startColour = LightColour(endColour, 50) - mem_dc.GradientFillLinear(rect, startColour, endColour, wx.SOUTH) - - # Draw the caption title and place the bitmap - # get the bitmap optimal position, and draw it - bmpPt, txtPt = wx.Point(), wx.Point() - bmpPt.y = (rect.height - self._props.Icon.GetHeight())/2 - bmpPt.x = 3 - mem_dc.DrawBitmap(self._props.Icon, bmpPt.x, bmpPt.y, True) - - # get the text position, and draw it - font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) - font.SetWeight(wx.BOLD) - mem_dc.SetFont(font) - fontHeight = mem_dc.GetCharHeight() - - txtPt.x = bmpPt.x + self._props.Icon.GetWidth() + 4 - txtPt.y = (rect.height - fontHeight)/2 - mem_dc.SetTextForeground(wx.WHITE) - mem_dc.DrawText("Opened tabs:", txtPt.x, txtPt.y) - mem_dc.SelectObject(wx.NullBitmap) - - dc.DrawBitmap(bmp, 0, 0) - - - def OnPanelEraseBg(self, event): - """ - Handles the ``wx.EVT_ERASE_BACKGROUND`` event for :class:`TabNavigatorWindow` top panel. - - :param `event`: a :class:`EraseEvent` event to be processed. - - :note: This is intentionally empty, to reduce flicker. - """ - - pass - - -# ---------------------------------------------------------------------- -# -- AuiTabContainer class implementation -- - -class AuiTabContainer(object): - """ - AuiTabContainer is a class which contains information about each tab. - It also can render an entire tab control to a specified DC. - It's not a window class itself, because this code will be used by - the :class:`AuiNotebook`, where it is disadvantageous to have separate - windows for each tab control in the case of "docked tabs". - - A derived class, :class:`AuiTabCtrl`, is an actual :class:`Window` - derived window - which can be used as a tab control in the normal sense. - """ - - def __init__(self, auiNotebook): - """ - Default class constructor. - Used internally, do not call it in your code! - - :param `auiNotebook`: the parent :class:`AuiNotebook` window. - """ - - self._tab_offset = 0 - self._agwFlags = 0 - self._art = TA.AuiDefaultTabArt() - - self._buttons = [] - self._pages = [] - self._tab_close_buttons = [] - - self._rect = wx.Rect() - self._auiNotebook = auiNotebook - - self.AddButton(AUI_BUTTON_LEFT, wx.LEFT) - self.AddButton(AUI_BUTTON_RIGHT, wx.RIGHT) - self.AddButton(AUI_BUTTON_WINDOWLIST, wx.RIGHT) - self.AddButton(AUI_BUTTON_CLOSE, wx.RIGHT) - - - def SetArtProvider(self, art): - """ - Instructs :class:`AuiTabContainer` to use art provider specified by parameter `art` - for all drawing calls. This allows plugable look-and-feel features. - - :param `art`: an art provider. - - :note: The previous art provider object, if any, will be deleted by :class:`AuiTabContainer`. - """ - - del self._art - self._art = art - - if self._art: - self._art.SetAGWFlags(self._agwFlags) - - - def GetArtProvider(self): - """ Returns the current art provider being used. """ - - return self._art - - - def SetAGWFlags(self, agwFlags): - """ - Sets the tab art flags. - - :param integer `agwFlags`: a combination of the following values: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook - ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet - ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet - ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook - ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab - ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging - ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control - ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width - ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed - ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available - ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar - ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab - ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs - ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close :class:`AuiNotebook` tabs by mouse middle button click - ``AUI_NB_SUB_NOTEBOOK`` This style is used by :class:`~lib.agw.aui.framemanager.AuiManager` to create automatic AuiNotebooks - ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present - ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows - ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items - ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser) - ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, - tabs cannot be dragged far enough outside of the notebook to become floating pages - ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default) - ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs - ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle - ==================================== ================================== - - .. todo:: Implementation of flags ``AUI_NB_RIGHT`` and ``AUI_NB_LEFT``. - - """ - - self._agwFlags = agwFlags - - # check for new close button settings - self.RemoveButton(AUI_BUTTON_LEFT) - self.RemoveButton(AUI_BUTTON_RIGHT) - self.RemoveButton(AUI_BUTTON_WINDOWLIST) - self.RemoveButton(AUI_BUTTON_CLOSE) - - if agwFlags & AUI_NB_SCROLL_BUTTONS: - self.AddButton(AUI_BUTTON_LEFT, wx.LEFT) - self.AddButton(AUI_BUTTON_RIGHT, wx.RIGHT) - - if agwFlags & AUI_NB_WINDOWLIST_BUTTON: - self.AddButton(AUI_BUTTON_WINDOWLIST, wx.RIGHT) - - if agwFlags & AUI_NB_CLOSE_BUTTON: - self.AddButton(AUI_BUTTON_CLOSE, wx.RIGHT) - - if self._art: - self._art.SetAGWFlags(self._agwFlags) - - - def GetAGWFlags(self): - """ - Returns the tab art flags. - - .. seealso:: :meth:`SetAGWFlags` for a list of possible return values. - """ - - return self._agwFlags - - - def SetNormalFont(self, font): - """ - Sets the normal font for drawing tab labels. - - :param Font `font`: the new font to use to draw tab labels in their normal, un-selected state. - """ - - self._art.SetNormalFont(font) - - - def SetSelectedFont(self, font): - """ - Sets the selected tab font for drawing tab labels. - - :param Font `font`: the new font to use to draw tab labels in their selected state. - """ - - self._art.SetSelectedFont(font) - - - def SetMeasuringFont(self, font): - """ - Sets the font for calculating text measurements. - - :param Font `font`: the new font to use to measure tab label text extents. - """ - - self._art.SetMeasuringFont(font) - - - def SetTabRect(self, rect): - """ - Sets the tab area rectangle. - - :param Rect `rect`: the available area for :class:`AuiTabContainer`. - """ - - self._rect = rect - - if self._art: - minMaxTabWidth = self._auiNotebook.GetMinMaxTabWidth() - self._art.SetSizingInfo(rect.GetSize(), len(self._pages), minMaxTabWidth) - - - def AddPage(self, page, info): - """ - Adds a page to the tab control. - - :param Window `page`: the window associated with this tab; - :param `info`: an instance of :class:`AuiNotebookPage`. - """ - - page_info = info - page_info.window = page - - self._pages.append(page_info) - - # let the art provider know how many pages we have - if self._art: - minMaxTabWidth = self._auiNotebook.GetMinMaxTabWidth() - self._art.SetSizingInfo(self._rect.GetSize(), len(self._pages), minMaxTabWidth) - - return True - - - def InsertPage(self, page, info, idx): - """ - Inserts a page in the tab control in the position specified by `idx`. - - :param Window `page`: the window associated with this tab; - :param `info`: an instance of :class:`AuiNotebookPage`; - :param integer `idx`: the page insertion index. - """ - - page_info = info - page_info.window = page - - if idx >= len(self._pages): - self._pages.append(page_info) - else: - self._pages.insert(idx, page_info) - - # let the art provider know how many pages we have - if self._art: - minMaxTabWidth = self._auiNotebook.GetMinMaxTabWidth() - self._art.SetSizingInfo(self._rect.GetSize(), len(self._pages), minMaxTabWidth) - - return True - - - def MovePage(self, page, new_idx): - """ - Moves a page in a new position specified by `new_idx`. - - :param Window `page`: the window associated with this tab; - :param integer `new_idx`: the new page position. - """ - - idx = self.GetIdxFromWindow(page) - if idx == -1: - return False - - # get page entry, make a copy of it - p = self.GetPage(idx) - - # remove old page entry - self.RemovePage(page) - - # insert page where it should be - self.InsertPage(page, p, new_idx) - - return True - - - def RemovePage(self, wnd): - """ - Removes a page from the tab control. - - :param `wnd`: an instance of :class:`Window`, a window associated with this tab. - """ - - minMaxTabWidth = self._auiNotebook.GetMinMaxTabWidth() - - for page in self._pages: - if page.window == wnd: - self._pages.remove(page) - self._tab_offset = min(self._tab_offset, len(self._pages) - 1) - - # let the art provider know how many pages we have - if self._art: - self._art.SetSizingInfo(self._rect.GetSize(), len(self._pages), minMaxTabWidth) - - return True - - return False - - - def SetActivePage(self, wndOrInt): - """ - Sets the :class:`AuiNotebook` active page. - - :param `wndOrInt`: an instance of :class:`Window` or an integer specifying a tab index. - """ - - if type(wndOrInt) == types.IntType: - - if wndOrInt >= len(self._pages): - return False - - wnd = self._pages[wndOrInt].window - - else: - wnd = wndOrInt - - found = False - - for indx, page in enumerate(self._pages): - if page.window == wnd: - page.active = True - found = True - else: - page.active = False - - return found - - - def SetNoneActive(self): - """ Sets all the tabs as inactive (non-selected). """ - - for page in self._pages: - page.active = False - - - def GetActivePage(self): - """ Returns the current selected tab or ``wx.NOT_FOUND`` if none is selected. """ - - for indx, page in enumerate(self._pages): - if page.active: - return indx - - return wx.NOT_FOUND - - - def GetWindowFromIdx(self, idx): - """ - Returns the window associated with the tab with index `idx`. - - :param integer `idx`: the tab index. - """ - - if idx >= len(self._pages): - return None - - return self._pages[idx].window - - - def GetIdxFromWindow(self, wnd): - """ - Returns the tab index based on the window `wnd` associated with it. - - :param `wnd`: an instance of :class:`Window`. - """ - - for indx, page in enumerate(self._pages): - if page.window == wnd: - return indx - - return wx.NOT_FOUND - - - def GetPage(self, idx): - """ - Returns the page specified by the given index. - - :param integer `idx`: the tab index. - """ - - if idx < 0 or idx >= len(self._pages): - raise Exception("Invalid Page index") - - return self._pages[idx] - - - def GetPages(self): - """ Returns a list of all the pages in this :class:`AuiTabContainer`. """ - - return self._pages - - - def GetPageCount(self): - """ Returns the number of pages in the :class:`AuiTabContainer`. """ - - return len(self._pages) - - - def GetEnabled(self, idx): - """ - Returns whether a tab is enabled or not. - - :param integer `idx`: the tab index. - """ - - if idx < 0 or idx >= len(self._pages): - return False - - return self._pages[idx].enabled - - - def EnableTab(self, idx, enable=True): - """ - Enables/disables a tab in the :class:`AuiTabContainer`. - - :param integer `idx`: the tab index; - :param bool `enable`: ``True`` to enable a tab, ``False`` to disable it. - """ - - if idx < 0 or idx >= len(self._pages): - raise Exception("Invalid Page index") - - self._pages[idx].enabled = enable - wnd = self.GetWindowFromIdx(idx) - wnd.Enable(enable) - - - def AddButton(self, id, location, normal_bitmap=wx.NullBitmap, disabled_bitmap=wx.NullBitmap): - """ - Adds a button in the tab area. - - :param integer `id`: the button identifier. This can be one of the following: - - ============================== ================================= - Button Identifier Description - ============================== ================================= - ``AUI_BUTTON_CLOSE`` Shows a close button on the tab area - ``AUI_BUTTON_WINDOWLIST`` Shows a window list button on the tab area - ``AUI_BUTTON_LEFT`` Shows a left button on the tab area - ``AUI_BUTTON_RIGHT`` Shows a right button on the tab area - ============================== ================================= - - :param integer `location`: the button location. Can be ``wx.LEFT`` or ``wx.RIGHT``; - :param Bitmap `normal_bitmap`: the bitmap for an enabled tab; - :param Bitmap `disabled_bitmap`: the bitmap for a disabled tab. - """ - - button = AuiTabContainerButton() - button.id = id - button.bitmap = normal_bitmap - button.dis_bitmap = disabled_bitmap - button.location = location - button.cur_state = AUI_BUTTON_STATE_NORMAL - - self._buttons.append(button) - - - def CloneButtons(self): - """ - Clones the tab area buttons when the :class:`AuiNotebook` is being split. - - :see: :meth:`AddButton` - - :note: Standard buttons for :class:`AuiNotebook` are not cloned, only custom ones. - """ - - singleton_list = [AUI_BUTTON_CLOSE, AUI_BUTTON_WINDOWLIST, AUI_BUTTON_LEFT, AUI_BUTTON_RIGHT] - clones = [] - - for button in self._buttons: - if button.id not in singleton_list: - new_button = AuiTabContainerButton() - new_button.id = button.id - new_button.bitmap = button.bitmap - new_button.dis_bitmap = button.dis_bitmap - new_button.location = button.location - clones.append(new_button) - - return clones - - - def RemoveButton(self, id): - """ - Removes a button from the tab area. - - :param integer `id`: the button identifier. See :meth:`AddButton` for a list of button identifiers. - - :see: :meth:`AddButton` - """ - - for button in self._buttons: - if button.id == id: - self._buttons.remove(button) - return - - - def GetTabOffset(self): - """ Returns the tab offset. """ - - return self._tab_offset - - - def SetTabOffset(self, offset): - """ - Sets the tab offset. - - :param integer `offset`: the tab offset. - """ - - self._tab_offset = offset - - - def Render(self, raw_dc, wnd): - """ - Renders the tab catalog to the specified :class:`DC`. - - It is a virtual function and can be overridden to provide custom drawing - capabilities. - - :param `raw_dc`: a :class:`DC` device context; - :param `wnd`: an instance of :class:`Window`. - """ - - if not raw_dc or not raw_dc.IsOk(): - return - - dc = wx.MemoryDC() - - # use the same layout direction as the window DC uses to ensure that the - # text is rendered correctly - dc.SetLayoutDirection(raw_dc.GetLayoutDirection()) - - page_count = len(self._pages) - button_count = len(self._buttons) - - # create off-screen bitmap - bmp = wx.EmptyBitmap(self._rect.GetWidth(), self._rect.GetHeight()) - dc.SelectObject(bmp) - - if not dc.IsOk(): - return - - # prepare the tab-close-button array - # make sure tab button entries which aren't used are marked as hidden - for i in xrange(page_count, len(self._tab_close_buttons)): - self._tab_close_buttons[i].cur_state = AUI_BUTTON_STATE_HIDDEN - - # make sure there are enough tab button entries to accommodate all tabs - while len(self._tab_close_buttons) < page_count: - tempbtn = AuiTabContainerButton() - tempbtn.id = AUI_BUTTON_CLOSE - tempbtn.location = wx.CENTER - tempbtn.cur_state = AUI_BUTTON_STATE_HIDDEN - self._tab_close_buttons.append(tempbtn) - - # find out if size of tabs is larger than can be - # afforded on screen - total_width = visible_width = 0 - tab_width = [0] * page_count - - for i in xrange(page_count): - page = self._pages[i] - - # determine if a close button is on this tab - close_button = False - if (self._agwFlags & AUI_NB_CLOSE_ON_ALL_TABS and page.hasCloseButton) or \ - (self._agwFlags & AUI_NB_CLOSE_ON_ACTIVE_TAB and page.active and page.hasCloseButton): - - close_button = True - - control = page.control - if control: - try: - control.GetSize() - except wx.PyDeadObjectError: - page.control = None - - size, x_extent = self._art.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active, - (close_button and [AUI_BUTTON_STATE_NORMAL] or \ - [AUI_BUTTON_STATE_HIDDEN])[0], page.control) - - if i+1 < page_count: - total_width += x_extent - tab_width[i] = x_extent - else: - total_width += size[0] - tab_width[i] = size[0] - - if i >= self._tab_offset: - if i+1 < page_count: - visible_width += x_extent - else: - visible_width += size[0] - - # Calculate the width of visible buttons - buttons_width = 0 - - for button in self._buttons: - if not (button.cur_state & AUI_BUTTON_STATE_HIDDEN): - buttons_width += button.rect.GetWidth() - - total_width += buttons_width - - if (total_width > self._rect.GetWidth() and page_count > 1) or self._tab_offset != 0: - - # show left/right buttons - for button in self._buttons: - if button.id == AUI_BUTTON_LEFT or \ - button.id == AUI_BUTTON_RIGHT: - - button.cur_state &= ~AUI_BUTTON_STATE_HIDDEN - - else: - - # hide left/right buttons - for button in self._buttons: - if button.id == AUI_BUTTON_LEFT or \ - button.id == AUI_BUTTON_RIGHT: - - button.cur_state |= AUI_BUTTON_STATE_HIDDEN - - # Re-calculate the width of visible buttons (may have been hidden/shown) - buttons_width = 0 - for button in self._buttons: - if not (button.cur_state & AUI_BUTTON_STATE_HIDDEN): - buttons_width += button.rect.GetWidth() - - # Shift the tab offset down to make use of available space - available_width = self._rect.GetWidth() - buttons_width - while self._tab_offset > 0 and visible_width + tab_width[self._tab_offset - 1] < available_width: - self._tab_offset -= 1 - visible_width += tab_width[self._tab_offset] - - # determine whether left button should be enabled - for button in self._buttons: - if button.id == AUI_BUTTON_LEFT: - if self._tab_offset == 0: - button.cur_state |= AUI_BUTTON_STATE_DISABLED - else: - button.cur_state &= ~AUI_BUTTON_STATE_DISABLED - - if button.id == AUI_BUTTON_RIGHT: - if visible_width < self._rect.GetWidth() - buttons_width: - button.cur_state |= AUI_BUTTON_STATE_DISABLED - else: - button.cur_state &= ~AUI_BUTTON_STATE_DISABLED - - # draw background - self._art.DrawBackground(dc, wnd, self._rect) - - # draw buttons - left_buttons_width = 0 - right_buttons_width = 0 - - # draw the buttons on the right side - offset = self._rect.x + self._rect.width - - for i in xrange(button_count): - button = self._buttons[button_count - i - 1] - - if button.location != wx.RIGHT: - continue - if button.cur_state & AUI_BUTTON_STATE_HIDDEN: - continue - - button_rect = wx.Rect(*self._rect) - button_rect.SetY(1) - button_rect.SetWidth(offset) - - button.rect = self._art.DrawButton(dc, wnd, button_rect, button, wx.RIGHT) - - offset -= button.rect.GetWidth() - right_buttons_width += button.rect.GetWidth() - - offset = 0 - - # draw the buttons on the left side - for i in xrange(button_count): - button = self._buttons[button_count - i - 1] - - if button.location != wx.LEFT: - continue - if button.cur_state & AUI_BUTTON_STATE_HIDDEN: - continue - - button_rect = wx.Rect(offset, 1, 1000, self._rect.height) - - button.rect = self._art.DrawButton(dc, wnd, button_rect, button, wx.LEFT) - - offset += button.rect.GetWidth() - left_buttons_width += button.rect.GetWidth() - - offset = left_buttons_width - - if offset == 0: - offset += self._art.GetIndentSize() - - # buttons before the tab offset must be set to hidden - for i in xrange(self._tab_offset): - self._tab_close_buttons[i].cur_state = AUI_BUTTON_STATE_HIDDEN - if self._pages[i].control: - if self._pages[i].control.IsShown(): - self._pages[i].control.Hide() - - # draw tab before tab offset - if self._tab_offset > 0: - page = self._pages[self._tab_offset - 1] - tab_button = self._tab_close_buttons[self._tab_offset - 1] - size, x_extent = self._art.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active, tab_button.cur_state, page.control) - - rect = wx.Rect(offset - x_extent, 0, self._rect.width - right_buttons_width - offset - x_extent - 2, self._rect.height) - clip_rect = wx.Rect(*self._rect) - clip_rect.x = offset - - dc.SetClippingRect(clip_rect) - self._art.DrawTab(dc, wnd, page, rect, tab_button.cur_state) - dc.DestroyClippingRegion() - - # draw the tabs - active = 999 - active_offset = 0 - - rect = wx.Rect(*self._rect) - rect.y = 0 - rect.height = self._rect.height - - for i in xrange(self._tab_offset, page_count): - - page = self._pages[i] - tab_button = self._tab_close_buttons[i] - - # determine if a close button is on this tab - if (self._agwFlags & AUI_NB_CLOSE_ON_ALL_TABS and page.hasCloseButton) or \ - (self._agwFlags & AUI_NB_CLOSE_ON_ACTIVE_TAB and page.active and page.hasCloseButton): - - if tab_button.cur_state == AUI_BUTTON_STATE_HIDDEN: - - tab_button.id = AUI_BUTTON_CLOSE - tab_button.cur_state = AUI_BUTTON_STATE_NORMAL - tab_button.location = wx.CENTER - - else: - - tab_button.cur_state = AUI_BUTTON_STATE_HIDDEN - - rect.x = offset - rect.width = self._rect.width - right_buttons_width - offset - 2 - - if rect.width <= 0: - break - - page.rect, tab_button.rect, x_extent = self._art.DrawTab(dc, wnd, page, rect, tab_button.cur_state) - - if page.active: - active = i - active_offset = offset - active_rect = wx.Rect(*rect) - - offset += x_extent - - lenPages = len(self._pages) - # make sure to deactivate buttons which are off the screen to the right - for j in xrange(i+1, len(self._tab_close_buttons)): - self._tab_close_buttons[j].cur_state = AUI_BUTTON_STATE_HIDDEN - if j > 0 and j <= lenPages: - if self._pages[j-1].control: - if self._pages[j-1].control.IsShown(): - self._pages[j-1].control.Hide() - - # draw the active tab again so it stands in the foreground - if active >= self._tab_offset and active < len(self._pages): - - page = self._pages[active] - tab_button = self._tab_close_buttons[active] - - rect.x = active_offset - dummy = self._art.DrawTab(dc, wnd, page, active_rect, tab_button.cur_state) - - raw_dc.Blit(self._rect.x, self._rect.y, self._rect.GetWidth(), self._rect.GetHeight(), dc, 0, 0) - - - def IsTabVisible(self, tabPage, tabOffset, dc, wnd): - """ - Returns whether a tab is visible or not. - - :param integer `tabPage`: the tab index; - :param integer `tabOffset`: the tab offset; - :param `dc`: a :class:`DC` device context; - :param `wnd`: an instance of :class:`Window` derived window. - """ - - if not dc or not dc.IsOk(): - return False - - page_count = len(self._pages) - button_count = len(self._buttons) - self.Render(dc, wnd) - - # Hasn't been rendered yet assume it's visible - if len(self._tab_close_buttons) < page_count: - return True - - if self._agwFlags & AUI_NB_SCROLL_BUTTONS: - # First check if both buttons are disabled - if so, there's no need to - # check further for visibility. - arrowButtonVisibleCount = 0 - for i in xrange(button_count): - - button = self._buttons[i] - if button.id == AUI_BUTTON_LEFT or \ - button.id == AUI_BUTTON_RIGHT: - - if button.cur_state & AUI_BUTTON_STATE_HIDDEN == 0: - arrowButtonVisibleCount += 1 - - # Tab must be visible - if arrowButtonVisibleCount == 0: - return True - - # If tab is less than the given offset, it must be invisible by definition - if tabPage < tabOffset: - return False - - # draw buttons - left_buttons_width = 0 - right_buttons_width = 0 - - offset = 0 - - # calculate size of the buttons on the right side - offset = self._rect.x + self._rect.width - - for i in xrange(button_count): - button = self._buttons[button_count - i - 1] - - if button.location != wx.RIGHT: - continue - if button.cur_state & AUI_BUTTON_STATE_HIDDEN: - continue - - offset -= button.rect.GetWidth() - right_buttons_width += button.rect.GetWidth() - - offset = 0 - - # calculate size of the buttons on the left side - for i in xrange(button_count): - button = self._buttons[button_count - i - 1] - - if button.location != wx.LEFT: - continue - if button.cur_state & AUI_BUTTON_STATE_HIDDEN: - continue - - offset += button.rect.GetWidth() - left_buttons_width += button.rect.GetWidth() - - offset = left_buttons_width - - if offset == 0: - offset += self._art.GetIndentSize() - - rect = wx.Rect(*self._rect) - rect.y = 0 - rect.height = self._rect.height - - # See if the given page is visible at the given tab offset (effectively scroll position) - for i in xrange(tabOffset, page_count): - - page = self._pages[i] - tab_button = self._tab_close_buttons[i] - - rect.x = offset - rect.width = self._rect.width - right_buttons_width - offset - 2 - - if rect.width <= 0: - return False # haven't found the tab, and we've run out of space, so return False - - size, x_extent = self._art.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active, tab_button.cur_state, page.control) - offset += x_extent - - if i == tabPage: - - # If not all of the tab is visible, and supposing there's space to display it all, - # we could do better so we return False. - if (self._rect.width - right_buttons_width - offset - 2) <= 0 and (self._rect.width - right_buttons_width - left_buttons_width) > x_extent: - return False - else: - return True - - # Shouldn't really get here, but if it does, assume the tab is visible to prevent - # further looping in calling code. - return True - - - def MakeTabVisible(self, tabPage, win): - """ - Make the tab visible if it wasn't already. - - :param integer `tabPage`: the tab index; - :param `win`: an instance of :class:`Window` derived window. - """ - - dc = wx.ClientDC(win) - - if not self.IsTabVisible(tabPage, self.GetTabOffset(), dc, win): - for i in xrange(len(self._pages)): - if self.IsTabVisible(tabPage, i, dc, win): - self.SetTabOffset(i) - win.Refresh() - return - - - def TabHitTest(self, x, y): - """ - TabHitTest() tests if a tab was hit, passing the window pointer - back if that condition was fulfilled. - - :param integer `x`: the mouse `x` position; - :param integer `y`: the mouse `y` position. - """ - - if not self._rect.Contains((x,y)): - return None - - btn = self.ButtonHitTest(x, y) - if btn: - if btn in self._buttons: - return None - - for i in xrange(self._tab_offset, len(self._pages)): - page = self._pages[i] - if page.rect.Contains((x,y)): - return page.window - - return None - - - def ButtonHitTest(self, x, y): - """ - Tests if a button was hit. - - :param integer `x`: the mouse `x` position; - :param integer `y`: the mouse `y` position. - - :returns: and instance of :class:`AuiTabContainerButton` if a button was hit, ``None`` otherwise. - """ - - if not self._rect.Contains((x,y)): - return None - - for button in self._buttons: - if button.rect.Contains((x,y)) and \ - (button.cur_state & (AUI_BUTTON_STATE_HIDDEN|AUI_BUTTON_STATE_DISABLED)) == 0: - return button - - for button in self._tab_close_buttons: - if button.rect.Contains((x,y)) and \ - (button.cur_state & (AUI_BUTTON_STATE_HIDDEN|AUI_BUTTON_STATE_DISABLED)) == 0: - return button - - return None - - - def DoShowHide(self): - """ - This function shows the active window, then hides all of the other windows - (in that order). - """ - - pages = self.GetPages() - - # show new active page first - for page in pages: - if page.active: - page.window.Show(True) - break - - # hide all other pages - for page in pages: - if not page.active: - page.window.Show(False) - - -# ---------------------------------------------------------------------- -# -- AuiTabCtrl class implementation -- - -class AuiTabCtrl(wx.PyControl, AuiTabContainer): - """ - This is an actual :class:`Window` - derived window which can be used as a tab control in the normal sense. - """ - - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, - style=wx.NO_BORDER|wx.WANTS_CHARS|wx.TAB_TRAVERSAL): - """ - Default class constructor. - Used internally, do not call it in your code! - - :param `parent`: the :class:`AuiNotebook` parent; - :param integer `id`: an identifier for the control: a value of -1 is taken to mean a default; - :param Point `pos`: the control position. A value of (-1, -1) indicates a default position, - chosen by either the windowing system or wxPython, depending on platform; - :param Size `size`: the control size. A value of (-1, -1) indicates a default size, - chosen by either the windowing system or wxPython, depending on platform; - :param integer `style`: the window style. - """ - - wx.PyControl.__init__(self, parent, id, pos, size, style, name="AuiTabCtrl") - AuiTabContainer.__init__(self, parent) - - self._click_pt = wx.Point(-1, -1) - self._is_dragging = False - self._hover_button = None - self._pressed_button = None - self._drag_image = None - self._drag_img_offset = (0, 0) - self._on_button = False - - self.Bind(wx.EVT_PAINT, self.OnPaint) - self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) - self.Bind(wx.EVT_SIZE, self.OnSize) - self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) - self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick) - self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) - self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown) - self.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp) - self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) - self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) - self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) - self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) - self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) - self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnCaptureLost) - self.Bind(wx.EVT_MOTION, self.OnMotion) - self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) - self.Bind(EVT_AUINOTEBOOK_BUTTON, self.OnButton) - - - def IsDragging(self): - """ Returns whether the user is dragging a tab with the mouse or not. """ - - return self._is_dragging - - - def GetDefaultBorder(self): - """ Returns the default border style for :class:`AuiTabCtrl`. """ - - return wx.BORDER_NONE - - - def OnPaint(self, event): - """ - Handles the ``wx.EVT_PAINT`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`PaintEvent` event to be processed. - """ - - dc = wx.PaintDC(self) - dc.SetFont(self.GetFont()) - - if self.GetPageCount() > 0: - self.Render(dc, self) - - - def OnEraseBackground(self, event): - """ - Handles the ``wx.EVT_ERASE_BACKGROUND`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`EraseEvent` event to be processed. - - :note: This is intentionally empty, to reduce flicker. - """ - - pass - - - def DoGetBestSize(self): - """ - Gets the size which best suits the window: for a control, it would be the - minimal size which doesn't truncate the control, for a panel - the same - size as it would have after a call to `Fit()`. - - :note: Overridden from :class:`PyControl`. - """ - - return wx.Size(self._rect.width, self._rect.height) - - - def OnSize(self, event): - """ - Handles the ``wx.EVT_SIZE`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`SizeEvent` event to be processed. - """ - - s = event.GetSize() - self.SetTabRect(wx.Rect(0, 0, s.GetWidth(), s.GetHeight())) - - - def OnLeftDown(self, event): - """ - Handles the ``wx.EVT_LEFT_DOWN`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - if not self.HasCapture(): - self.CaptureMouse() - - self._click_pt = wx.Point(-1, -1) - self._is_dragging = False - self._click_tab = None - self._pressed_button = None - - wnd = self.TabHitTest(event.GetX(), event.GetY()) - - if wnd is not None: - new_selection = self.GetIdxFromWindow(wnd) - - # AuiNotebooks always want to receive this event - # even if the tab is already active, because they may - # have multiple tab controls - if (new_selection != self.GetActivePage() or isinstance(self.GetParent(), AuiNotebook)) and \ - not self._hover_button: - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, self.GetId()) - e.SetSelection(new_selection) - e.SetOldSelection(self.GetActivePage()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - self._click_pt.x = event.GetX() - self._click_pt.y = event.GetY() - self._click_tab = wnd - - wnd.SetFocus() - else: - page_index = self.GetActivePage() - if page_index != wx.NOT_FOUND: - self.GetWindowFromIdx(page_index).SetFocus() - - self._hover_button = self.ButtonHitTest(event.GetX(), event.GetY()) - - if self._hover_button: - self._pressed_button = self._hover_button - self._pressed_button.cur_state = AUI_BUTTON_STATE_PRESSED - self._on_button = True - - self.Refresh() - self.Update() - - - def OnCaptureLost(self, event): - """ - Handles the ``wx.EVT_MOUSE_CAPTURE_LOST`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseCaptureLostEvent` event to be processed. - """ - - if self._is_dragging: - self._is_dragging = False - self._on_button = False - - if self._drag_image: - self._drag_image.EndDrag() - del self._drag_image - self._drag_image = None - - event = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_CANCEL_DRAG, self.GetId()) - event.SetSelection(self.GetIdxFromWindow(self._click_tab)) - event.SetOldSelection(event.GetSelection()) - event.SetEventObject(self) - self.GetEventHandler().ProcessEvent(event) - - - def OnLeftUp(self, event): - """ - Handles the ``wx.EVT_LEFT_UP`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - self._on_button = False - - if self._is_dragging: - - if self.HasCapture(): - self.ReleaseMouse() - - self._is_dragging = False - if self._drag_image: - self._drag_image.EndDrag() - del self._drag_image - self._drag_image = None - self.GetParent().Refresh() - - evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, self.GetId()) - evt.SetSelection(self.GetIdxFromWindow(self._click_tab)) - evt.SetOldSelection(evt.GetSelection()) - evt.SetEventObject(self) - self.GetEventHandler().ProcessEvent(evt) - - return - - self.GetParent()._mgr.HideHint() - - if self.HasCapture(): - self.ReleaseMouse() - - if self._hover_button: - self._pressed_button = self._hover_button - self._hover_button.cur_state = AUI_BUTTON_STATE_NORMAL - - if self._pressed_button: - - # make sure we're still clicking the button - button = self.ButtonHitTest(event.GetX(), event.GetY()) - - if button is None: - return - - if button != self._pressed_button: - self._pressed_button = None - return - - self.Refresh() - self.Update() - - if self._pressed_button.cur_state & AUI_BUTTON_STATE_DISABLED == 0: - - evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BUTTON, self.GetId()) - evt.SetSelection(self.GetIdxFromWindow(self._click_tab)) - evt.SetInt(self._pressed_button.id) - evt.SetEventObject(self) - eventHandler = self.GetEventHandler() - - if eventHandler is not None: - eventHandler.ProcessEvent(evt) - - self._pressed_button = None - - self._click_pt = wx.Point(-1, -1) - self._is_dragging = False - self._click_tab = None - - - def OnMiddleUp(self, event): - """ - Handles the ``wx.EVT_MIDDLE_UP`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - eventHandler = self.GetEventHandler() - if not isinstance(eventHandler, AuiTabCtrl): - event.Skip() - return - - x, y = event.GetX(), event.GetY() - wnd = self.TabHitTest(x, y) - - if wnd: - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, self.GetId()) - e.SetEventObject(self) - e.Page = wnd - e.SetSelection(self.GetIdxFromWindow(wnd)) - self.GetEventHandler().ProcessEvent(e) - elif not self.ButtonHitTest(x, y): - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_UP, self.GetId()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def OnMiddleDown(self, event): - """ - Handles the ``wx.EVT_MIDDLE_DOWN`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - eventHandler = self.GetEventHandler() - if not isinstance(eventHandler, AuiTabCtrl): - event.Skip() - return - - x, y = event.GetX(), event.GetY() - wnd = self.TabHitTest(x, y) - - if wnd: - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, self.GetId()) - e.SetEventObject(self) - e.Page = wnd - e.SetSelection(self.GetIdxFromWindow(wnd)) - self.GetEventHandler().ProcessEvent(e) - elif not self.ButtonHitTest(x, y): - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_MIDDLE_DOWN, self.GetId()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def OnRightUp(self, event): - """ - Handles the ``wx.EVT_RIGHT_UP`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - x, y = event.GetX(), event.GetY() - wnd = self.TabHitTest(x, y) - - if wnd: - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, self.GetId()) - e.SetEventObject(self) - e.Selection = self.GetIdxFromWindow(wnd) - e.Page = wnd - self.GetEventHandler().ProcessEvent(e) - elif not self.ButtonHitTest(x, y): - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_UP, self.GetId()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def OnRightDown(self, event): - """ - Handles the ``wx.EVT_RIGHT_DOWN`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - x, y = event.GetX(), event.GetY() - wnd = self.TabHitTest(x, y) - - if wnd: - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, self.GetId()) - e.SetEventObject(self) - e.SetSelection(self.GetIdxFromWindow(wnd)) - e.Page = wnd - self.GetEventHandler().ProcessEvent(e) - elif not self.ButtonHitTest(x, y): - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_RIGHT_DOWN, self.GetId()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def OnLeftDClick(self, event): - """ - Handles the ``wx.EVT_LEFT_DCLICK`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - x, y = event.GetX(), event.GetY() - wnd = self.TabHitTest(x, y) - - if wnd: - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_DCLICK, self.GetId()) - e.SetEventObject(self) - e.SetSelection(self.GetIdxFromWindow(wnd)) - e.Page = wnd - self.GetEventHandler().ProcessEvent(e) - elif not self.ButtonHitTest(x, y): - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, self.GetId()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def OnMotion(self, event): - """ - Handles the ``wx.EVT_MOTION`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - pos = event.GetPosition() - - # check if the mouse is hovering above a button - - button = self.ButtonHitTest(pos.x, pos.y) - wnd = self.TabHitTest(pos.x, pos.y) - - if wnd is not None: - mouse_tab = self.GetIdxFromWindow(wnd) - if not self._pages[mouse_tab].enabled: - self._hover_button = None - return - - if self._on_button: - return - - if button: - - if self._hover_button and button != self._hover_button: - self._hover_button.cur_state = AUI_BUTTON_STATE_NORMAL - self._hover_button = None - self.Refresh() - self.Update() - - if button.cur_state != AUI_BUTTON_STATE_HOVER: - button.cur_state = AUI_BUTTON_STATE_HOVER - self.Refresh() - self.Update() - self._hover_button = button - return - - else: - - if self._hover_button: - self._hover_button.cur_state = AUI_BUTTON_STATE_NORMAL - self._hover_button = None - self.Refresh() - self.Update() - - if not event.LeftIsDown() or self._click_pt == wx.Point(-1, -1): - return - - if not self.HasCapture(): - return - - wnd = self.TabHitTest(pos.x, pos.y) - - if not self._is_dragging: - - drag_x_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_X) - drag_y_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_Y) - - if abs(pos.x - self._click_pt.x) > drag_x_threshold or \ - abs(pos.y - self._click_pt.y) > drag_y_threshold: - - self._is_dragging = True - - if self._drag_image: - self._drag_image.EndDrag() - del self._drag_image - self._drag_image = None - - if self._agwFlags & AUI_NB_DRAW_DND_TAB: - # Create the custom draw image from the icons and the text of the item - mouse_tab = self.GetIdxFromWindow(wnd) - page = self._pages[mouse_tab] - tab_button = self._tab_close_buttons[mouse_tab] - self._drag_image = TabDragImage(self, page, tab_button.cur_state, self._art) - - if self._agwFlags & AUI_NB_TAB_FLOAT: - self._drag_image.BeginDrag(wx.Point(0,0), self, fullScreen=True) - else: - self._drag_image.BeginDragBounded(wx.Point(0,0), self, self.GetParent()) - - # Capture the mouse cursor position offset relative to - # The tab image location - self._drag_img_offset = (pos[0] - page.rect.x, - pos[1] - page.rect.y) - - self._drag_image.Show() - - if not wnd: - evt2 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, self.GetId()) - evt2.SetSelection(self.GetIdxFromWindow(self._click_tab)) - evt2.SetOldSelection(evt2.GetSelection()) - evt2.SetEventObject(self) - self.GetEventHandler().ProcessEvent(evt2) - if evt2.GetDispatched(): - return - - evt3 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, self.GetId()) - evt3.SetSelection(self.GetIdxFromWindow(self._click_tab)) - evt3.SetOldSelection(evt3.GetSelection()) - evt3.SetEventObject(self) - self.GetEventHandler().ProcessEvent(evt3) - - if self._drag_image: - # Apply the drag images offset - pos -= self._drag_img_offset - self._drag_image.Move(pos) - - - def OnLeaveWindow(self, event): - """ - Handles the ``wx.EVT_LEAVE_WINDOW`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`MouseEvent` event to be processed. - """ - - if self._hover_button: - self._hover_button.cur_state = AUI_BUTTON_STATE_NORMAL - self._hover_button = None - self.Refresh() - self.Update() - - - def OnButton(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_BUTTON`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - button = event.GetInt() - - if button == AUI_BUTTON_LEFT or button == AUI_BUTTON_RIGHT: - if button == AUI_BUTTON_LEFT: - if self.GetTabOffset() > 0: - - self.SetTabOffset(self.GetTabOffset()-1) - self.Refresh() - self.Update() - else: - self.SetTabOffset(self.GetTabOffset()+1) - self.Refresh() - self.Update() - - elif button == AUI_BUTTON_WINDOWLIST: - idx = self.GetArtProvider().ShowDropDown(self, self._pages, self.GetActivePage()) - - if idx != -1: - - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, self.GetId()) - e.SetSelection(idx) - e.SetOldSelection(self.GetActivePage()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - else: - event.Skip() - - - def OnSetFocus(self, event): - """ - Handles the ``wx.EVT_SET_FOCUS`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`FocusEvent` event to be processed. - """ - - self.Refresh() - - - def OnKillFocus(self, event): - """ - Handles the ``wx.EVT_KILL_FOCUS`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`FocusEvent` event to be processed. - """ - - self.Refresh() - - - def OnKeyDown(self, event): - """ - Handles the ``wx.EVT_KEY_DOWN`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`KeyEvent` event to be processed. - """ - - key = event.GetKeyCode() - nb = self.GetParent() - - if key == wx.WXK_LEFT: - nb.AdvanceSelection(False) - self.SetFocus() - - elif key == wx.WXK_RIGHT: - nb.AdvanceSelection(True) - self.SetFocus() - - elif key == wx.WXK_HOME: - newPage = 0 - nb.SetSelection(newPage) - self.SetFocus() - - elif key == wx.WXK_END: - newPage = nb.GetPageCount() - 1 - nb.SetSelection(newPage) - self.SetFocus() - - elif key == wx.WXK_TAB: - if not event.ControlDown(): - flags = 0 - if not event.ShiftDown(): flags |= wx.NavigationKeyEvent.IsForward - if event.CmdDown(): flags |= wx.NavigationKeyEvent.WinChange - self.Navigate(flags) - else: - - if not nb or not isinstance(nb, AuiNotebook): - event.Skip() - return - - bForward = bWindowChange = 0 - if not event.ShiftDown(): bForward |= wx.NavigationKeyEvent.IsForward - if event.CmdDown(): bWindowChange |= wx.NavigationKeyEvent.WinChange - - keyEvent = wx.NavigationKeyEvent() - keyEvent.SetDirection(bForward) - keyEvent.SetWindowChange(bWindowChange) - keyEvent.SetFromTab(True) - keyEvent.SetEventObject(nb) - - if not nb.GetEventHandler().ProcessEvent(keyEvent): - - # Not processed? Do an explicit tab into the page. - win = self.GetWindowFromIdx(self.GetActivePage()) - if win: - win.SetFocus() - - self.SetFocus() - - return - - else: - event.Skip() - - - def OnKeyDown2(self, event): - """ - Handles the ``wx.EVT_KEY_DOWN`` event for :class:`AuiTabCtrl`. - - :param `event`: a :class:`KeyEvent` event to be processed. - - .. deprecated:: 0.6 - This implementation is now deprecated. Refer to :meth:`OnKeyDown` for the correct one. - """ - - if self.GetActivePage() == -1: - event.Skip() - return - - # We can't leave tab processing to the system on Windows, tabs and keys - # get eaten by the system and not processed properly if we specify both - # wxTAB_TRAVERSAL and wxWANTS_CHARS. And if we specify just wxTAB_TRAVERSAL, - # we don't key arrow key events. - - key = event.GetKeyCode() - - if key == wx.WXK_NUMPAD_PAGEUP: - key = wx.WXK_PAGEUP - if key == wx.WXK_NUMPAD_PAGEDOWN: - key = wx.WXK_PAGEDOWN - if key == wx.WXK_NUMPAD_HOME: - key = wx.WXK_HOME - if key == wx.WXK_NUMPAD_END: - key = wx.WXK_END - if key == wx.WXK_NUMPAD_LEFT: - key = wx.WXK_LEFT - if key == wx.WXK_NUMPAD_RIGHT: - key = wx.WXK_RIGHT - - if key == wx.WXK_TAB or key == wx.WXK_PAGEUP or key == wx.WXK_PAGEDOWN: - - bCtrlDown = event.ControlDown() - bShiftDown = event.ShiftDown() - - bForward = (key == wx.WXK_TAB and not bShiftDown) or (key == wx.WXK_PAGEDOWN) - bWindowChange = (key == wx.WXK_PAGEUP) or (key == wx.WXK_PAGEDOWN) or bCtrlDown - bFromTab = (key == wx.WXK_TAB) - - nb = self.GetParent() - if not nb or not isinstance(nb, AuiNotebook): - event.Skip() - return - - keyEvent = wx.NavigationKeyEvent() - keyEvent.SetDirection(bForward) - keyEvent.SetWindowChange(bWindowChange) - keyEvent.SetFromTab(bFromTab) - keyEvent.SetEventObject(nb) - - if not nb.GetEventHandler().ProcessEvent(keyEvent): - - # Not processed? Do an explicit tab into the page. - win = self.GetWindowFromIdx(self.GetActivePage()) - if win: - win.SetFocus() - - return - - if len(self._pages) < 2: - event.Skip() - return - - newPage = -1 - - if self.GetLayoutDirection() == wx.Layout_RightToLeft: - forwardKey = wx.WXK_LEFT - backwardKey = wx.WXK_RIGHT - else: - forwardKey = wx.WXK_RIGHT - backwardKey = wx.WXK_LEFT - - if key == forwardKey: - if self.GetActivePage() == -1: - newPage = 0 - elif self.GetActivePage() < len(self._pages) - 1: - newPage = self.GetActivePage() + 1 - - elif key == backwardKey: - if self.GetActivePage() == -1: - newPage = len(self._pages) - 1 - elif self.GetActivePage() > 0: - newPage = self.GetActivePage() - 1 - - elif key == wx.WXK_HOME: - newPage = 0 - - elif key == wx.WXK_END: - newPage = len(self._pages) - 1 - - else: - event.Skip() - - if newPage != -1: - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, self.GetId()) - e.SetSelection(newPage) - e.SetOldSelection(newPage) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - else: - event.Skip() - - -# ---------------------------------------------------------------------- - -class TabFrame(wx.PyWindow): - """ - TabFrame is an interesting case. It's important that all child pages - of the multi-notebook control are all actually children of that control - (and not grandchildren). TabFrame facilitates this. There is one - instance of TabFrame for each tab control inside the multi-notebook. - - It's important to know that TabFrame is not a real window, but it merely - used to capture the dimensions/positioning of the internal tab control and - it's managed page windows. - """ - - def __init__(self, parent): - """ - Default class constructor. - Used internally, do not call it in your code! - """ - - pre = wx.PrePyWindow() - - self._tabs = None - self._rect = wx.Rect(0, 0, 200, 200) - self._tab_ctrl_height = 20 - self._tab_rect = wx.Rect() - self._parent = parent - - self.PostCreate(pre) - - - def SetTabCtrlHeight(self, h): - """ - Sets the tab control height. - - :param integer `h`: the tab area height. - """ - - self._tab_ctrl_height = h - - - def DoSetSize(self, x, y, width, height, flags=wx.SIZE_AUTO): - """ - Sets the position and size of the window in pixels. The `flags` - parameter indicates the interpretation of the other params if they are - equal to -1. - - :param integer `x`: the window `x` position; - :param integer `y`: the window `y` position; - :param integer `width`: the window width; - :param integer `height`: the window height; - :param integer `flags`: may have one of this bit set: - - =================================== ====================================== - Size Flags Description - =================================== ====================================== - ``wx.SIZE_AUTO`` A -1 indicates that a class-specific default should be used. - ``wx.SIZE_AUTO_WIDTH`` A -1 indicates that a class-specific default should be used for the width. - ``wx.SIZE_AUTO_HEIGHT`` A -1 indicates that a class-specific default should be used for the height. - ``wx.SIZE_USE_EXISTING`` Existing dimensions should be used if -1 values are supplied. - ``wx.SIZE_ALLOW_MINUS_ONE`` Allow dimensions of -1 and less to be interpreted as real dimensions, not default values. - ``wx.SIZE_FORCE`` Normally, if the position and the size of the window are already the same as the - parameters of this function, nothing is done. but with this flag a window resize - may be forced even in this case (supported in wx 2.6.2 and later and only implemented - for MSW and ignored elsewhere currently) - =================================== ====================================== - - :note: Overridden from :class:`PyControl`. - """ - - self._rect = wx.Rect(x, y, max(1, width), max(1, height)) - self.DoSizing() - - - def DoGetSize(self): - """ - Returns the window size. - - :note: Overridden from :class:`PyControl`. - """ - - return self._rect.width, self._rect.height - - - def DoGetClientSize(self): - """ - Returns the window client size. - - :note: Overridden from :class:`PyControl`. - """ - - return self._rect.width, self._rect.height - - - def Show(self, show=True): - """ - Shows/hides the window. - - :param bool `show`: ``True`` to show the window, ``False`` otherwise. - - :note: - - Overridden from :class:`PyControl`, this method always returns ``False`` as - :class:`TabFrame` should never be phisically shown on screen. - """ - - return False - - - def DoSizing(self): - """ Does the actual sizing of the tab control. """ - - if not self._tabs: - return - - hideOnSingle = ((self._tabs.GetAGWFlags() & AUI_NB_HIDE_ON_SINGLE_TAB) and \ - self._tabs.GetPageCount() <= 1) - - if not hideOnSingle and not self._parent._hide_tabs: - tab_height = self._tab_ctrl_height - - self._tab_rect = wx.Rect(self._rect.x, self._rect.y, self._rect.width, self._tab_ctrl_height) - - if self._tabs.GetAGWFlags() & AUI_NB_BOTTOM: - self._tab_rect = wx.Rect(self._rect.x, self._rect.y + self._rect.height - tab_height, - self._rect.width, tab_height) - self._tabs.SetDimensions(self._rect.x, self._rect.y + self._rect.height - tab_height, - self._rect.width, tab_height) - self._tabs.SetTabRect(wx.Rect(0, 0, self._rect.width, tab_height)) - - else: - - self._tab_rect = wx.Rect(self._rect.x, self._rect.y, self._rect.width, tab_height) - self._tabs.SetDimensions(self._rect.x, self._rect.y, self._rect.width, tab_height) - self._tabs.SetTabRect(wx.Rect(0, 0, self._rect.width, tab_height)) - - # TODO: elif (GetAGWFlags() & AUI_NB_LEFT) - # TODO: elif (GetAGWFlags() & AUI_NB_RIGHT) - - self._tabs.Refresh() - self._tabs.Update() - - else: - - tab_height = 0 - self._tabs.SetDimensions(self._rect.x, self._rect.y, self._rect.width, tab_height) - self._tabs.SetTabRect(wx.Rect(0, 0, self._rect.width, tab_height)) - - pages = self._tabs.GetPages() - - for page in pages: - - height = self._rect.height - tab_height - - if height < 0: - # avoid passing negative height to wx.Window.SetSize(), this - # results in assert failures/GTK+ warnings - height = 0 - - if self._tabs.GetAGWFlags() & AUI_NB_BOTTOM: - page.window.SetDimensions(self._rect.x, self._rect.y, self._rect.width, height) - - else: - page.window.SetDimensions(self._rect.x, self._rect.y + tab_height, - self._rect.width, height) - - # TODO: elif (GetAGWFlags() & AUI_NB_LEFT) - # TODO: elif (GetAGWFlags() & AUI_NB_RIGHT) - - if repr(page.window.__class__).find("AuiMDIChildFrame") >= 0: - page.window.ApplyMDIChildFrameRect() - - - def Update(self): - """ - Calling this method immediately repaints the invalidated area of the window - and all of its children recursively while this would usually only happen when - the flow of control returns to the event loop. - - :note: Notice that this function doesn't invalidate any area of the window so - nothing happens if nothing has been invalidated (i.e. marked as requiring a redraw). - Use `Refresh` first if you want to immediately redraw the window unconditionally. - - :note: Overridden from :class:`PyControl`. - """ - - # does nothing - pass - - -# ---------------------------------------------------------------------- -# -- AuiNotebook class implementation -- - -class AuiNotebook(wx.PyPanel): - """ - AuiNotebook is a notebook control which implements many features common in applications with dockable panes. - Specifically, AuiNotebook implements functionality which allows the user to rearrange tab - order via drag-and-drop, split the tab window into many different splitter configurations, and toggle - through different themes to customize the control's look and feel. - - An effort has been made to try to maintain an API as similar to that of :class:`Notebook`. - - The default theme that is used is :class:`~lib.agw.aui.tabart.AuiDefaultTabArt`, which provides a modern, glossy - look and feel. The theme can be changed by calling :meth:`AuiNotebook.SetArtProvider`. - """ - - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, - style=0, agwStyle=AUI_NB_DEFAULT_STYLE, name="AuiNotebook"): - """ - Default class constructor. - - :param Window `parent`: the :class:`AuiNotebook` parent; - :param integer `id`: an identifier for the control: a value of -1 is taken to mean a default; - :param Point `pos`: the control position. A value of (-1, -1) indicates a default position, - chosen by either the windowing system or wxPython, depending on platform; - :param Size `size`: the control size. A value of (-1, -1) indicates a default size, - chosen by either the windowing system or wxPython, depending on platform; - :param integer `style`: the underlying :class:`PyPanel` window style; - :param integer `agwStyle`: the AGW-specific window style. This can be a combination of the following bits: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook - ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet. - ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet. - ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook - ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab - ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging - ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control - ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width - ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed - ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available - ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar - ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab - ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs - ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close :class:`AuiNotebook` tabs by mouse middle button click - ``AUI_NB_SUB_NOTEBOOK`` This style is used by :class:`~lib.agw.aui.framemanager.AuiManager` to create automatic AuiNotebooks - ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present - ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows - ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items - ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser) - ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, - tabs cannot be dragged far enough outside of the notebook to become floating pages - ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default) - ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs - ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle - ==================================== ================================== - - Default value for `agwStyle` is: - ``AUI_NB_DEFAULT_STYLE`` = ``AUI_NB_TOP`` | ``AUI_NB_TAB_SPLIT`` | ``AUI_NB_TAB_MOVE`` | ``AUI_NB_SCROLL_BUTTONS`` | ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` | ``AUI_NB_MIDDLE_CLICK_CLOSE`` | ``AUI_NB_DRAW_DND_TAB`` - - :param string `name`: the window name. - """ - - self._curpage = -1 - self._tab_id_counter = AuiBaseTabCtrlId - self._dummy_wnd = None - self._hide_tabs = False - self._sash_dclick_unsplit = False - self._tab_ctrl_height = 20 - self._requested_bmp_size = wx.Size(-1, -1) - self._requested_tabctrl_height = -1 - self._textCtrl = None - self._tabBounds = (-1, -1) - self._click_tab = None - - wx.PyPanel.__init__(self, parent, id, pos, size, style|wx.BORDER_NONE|wx.TAB_TRAVERSAL, name=name) - self._mgr = framemanager.AuiManager() - self._tabs = AuiTabContainer(self) - - self.InitNotebook(agwStyle) - - NavigatorProps = property(lambda self: self._navProps) - - - def Destroy(self): - """ - Destroys the window safely. - - Use this function instead of the ``del`` operator, since different window - classes can be destroyed differently. Frames and dialogs are not destroyed - immediately when this function is called -- they are added to a list of - windows to be deleted on idle time, when all the window's events have been - processed. This prevents problems with events being sent to non-existent windows. - - :return: ``True`` if the window has either been successfully deleted, or - it has been added to the list of windows pending real deletion. - - .. note:: - - This method has been added to safely un-initialize the underlying - :class:`~lib.agw.aui.framemanager.AuiManager` which manages the :class:`AuiNotebook` - layout (i.e., tab split, re-ordering, tab floating etc...). - - """ - - self._mgr.UnInit() - return wx.PyPanel.Destroy(self) - - - def __getitem__(self, index): - """ - More Pythonic way to get a specific page, also useful for iterating - over all pages. - - :param integer `index`: the page index. - - .. note:: - - This method makes easier to iterate over all the pages in the notebook, i.e. you can - safely do:: - - for page in notebook: - DoSomething(page) - - - """ - - if index < self.GetPageCount(): - return self.GetPage(index) - else: - raise IndexError("Invalid page index") - - - def GetTabContainer(self): - """ Returns the instance of :class:`AuiTabContainer`. """ - - return self._tabs - - - def InitNotebook(self, agwStyle): - """ - Contains common initialization code called by all constructors. - - :param integer `agwStyle`: the notebook style. - - :see: :meth:`~AuiNotebook.__init__` for a list of available `agwStyle` bits. - """ - - self._agwFlags = agwStyle - - self._popupWin = None - self._imageList = None - self._navProps = TabNavigatorProps() - self._last_drag_x = 0 - - self._normal_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) - self._selected_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) - self._selected_font.SetWeight(wx.BOLD) - - self.SetArtProvider(TA.AuiDefaultTabArt()) - - self._dummy_wnd = wx.Window(self, wx.ID_ANY, wx.Point(0, 0), wx.Size(0, 0)) - self._dummy_wnd.SetSize((200, 200)) - self._dummy_wnd.Show(False) - - self._mgr.SetManagedWindow(self) - self._mgr.SetAGWFlags(AUI_MGR_DEFAULT) - self._mgr.SetDockSizeConstraint(1.0, 1.0) # no dock size constraint - - self._mgr.AddPane(self._dummy_wnd, framemanager.AuiPaneInfo().Name("dummy").Bottom().CaptionVisible(False).Show(False)) - self._mgr.Update() - - self.Bind(wx.EVT_SIZE, self.OnSize) - self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocusNotebook) - self.Bind(EVT_AUINOTEBOOK_PAGE_CHANGING, self.OnTabClicked, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_BEGIN_DRAG, self.OnTabBeginDrag, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_END_DRAG, self.OnTabEndDrag, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_DRAG_MOTION, self.OnTabDragMotion, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_CANCEL_DRAG, self.OnTabCancelDrag, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_BUTTON, self.OnTabButton, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_TAB_MIDDLE_DOWN, self.OnTabMiddleDown, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_TAB_MIDDLE_UP, self.OnTabMiddleUp, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_TAB_RIGHT_DOWN, self.OnTabRightDown, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_TAB_RIGHT_UP, self.OnTabRightUp, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_BG_DCLICK, self.OnTabBgDClick, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - self.Bind(EVT_AUINOTEBOOK_TAB_DCLICK, self.OnTabDClick, - id=AuiBaseTabCtrlId, id2=AuiBaseTabCtrlId+500) - - self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKeyNotebook) - - - def SetArtProvider(self, art): - """ - Sets the art provider to be used by the notebook. - - :param `art`: an art provider. - """ - - self._tabs.SetArtProvider(art) - self.UpdateTabCtrlHeight(force=True) - - - def SavePerspective(self): - """ - Saves the entire user interface layout into an encoded string, which can then - be stored by the application (probably using :class:`Config`). When a perspective - is restored using :meth:`LoadPerspective`, the entire user interface will return - to the state it was when the perspective was saved. - """ - - # Build list of panes/tabs - tabs = "" - all_panes = self._mgr.GetAllPanes() - - for pane in all_panes: - - if pane.name == "dummy": - continue - - tabframe = pane.window - - if tabs: - tabs += "|" - - tabs += pane.name + "=" - - # add tab id's - page_count = tabframe._tabs.GetPageCount() - - for p in xrange(page_count): - - page = tabframe._tabs.GetPage(p) - page_idx = self._tabs.GetIdxFromWindow(page.window) - - if p: - tabs += "," - - if p == tabframe._tabs.GetActivePage(): - tabs += "+" - elif page_idx == self._curpage: - tabs += "*" - - tabs += "%u"%page_idx - - tabs += "@" - - # Add frame perspective - tabs += self._mgr.SavePerspective() - - return tabs - - - def LoadPerspective(self, layout): - """ - Loads a layout which was saved with :meth:`SavePerspective`. - - :param string `layout`: a string which contains a saved :class:`AuiNotebook` layout. - """ - - # Remove all tab ctrls (but still keep them in main index) - tab_count = self._tabs.GetPageCount() - for i in xrange(tab_count): - wnd = self._tabs.GetWindowFromIdx(i) - - # find out which onscreen tab ctrl owns this tab - ctrl, ctrl_idx = self.FindTab(wnd) - if not ctrl: - return False - - # remove the tab from ctrl - if not ctrl.RemovePage(wnd): - return False - - self.RemoveEmptyTabFrames() - - sel_page = 0 - tabs = layout[0:layout.index("@")] - to_break1 = False - - while 1: - - if "|" not in tabs: - to_break1 = True - tab_part = tabs - else: - tab_part = tabs[0:tabs.index('|')] - - if "=" not in tab_part: - # No pages in this perspective... - return False - - # Get pane name - pane_name = tab_part[0:tab_part.index("=")] - - # create a new tab frame - new_tabs = TabFrame(self) - self._tab_id_counter += 1 - new_tabs._tabs = AuiTabCtrl(self, self._tab_id_counter) - new_tabs._tabs.SetArtProvider(self._tabs.GetArtProvider().Clone()) - new_tabs.SetTabCtrlHeight(self._tab_ctrl_height) - new_tabs._tabs.SetAGWFlags(self._agwFlags) - dest_tabs = new_tabs._tabs - - # create a pane info structure with the information - # about where the pane should be added - pane_info = framemanager.AuiPaneInfo().Name(pane_name).Bottom().CaptionVisible(False) - self._mgr.AddPane(new_tabs, pane_info) - - # Get list of tab id's and move them to pane - tab_list = tab_part[tab_part.index("=")+1:] - to_break2, active_found = False, False - - while 1: - if "," not in tab_list: - to_break2 = True - tab = tab_list - else: - tab = tab_list[0:tab_list.index(",")] - tab_list = tab_list[tab_list.index(",")+1:] - - # Check if this page has an 'active' marker - c = tab[0] - if c in ['+', '*']: - tab = tab[1:] - - tab_idx = int(tab) - if tab_idx >= self.GetPageCount(): - to_break1 = True - break - - # Move tab to pane - page = self._tabs.GetPage(tab_idx) - newpage_idx = dest_tabs.GetPageCount() - dest_tabs.InsertPage(page.window, page, newpage_idx) - - if c == '+': - dest_tabs.SetActivePage(newpage_idx) - active_found = True - elif c == '*': - sel_page = tab_idx - - if to_break2: - break - - if not active_found: - dest_tabs.SetActivePage(0) - - new_tabs.DoSizing() - dest_tabs.DoShowHide() - dest_tabs.Refresh() - - if to_break1: - break - - tabs = tabs[tabs.index('|')+1:] - - # Load the frame perspective - frames = layout[layout.index('@')+1:] - self._mgr.LoadPerspective(frames) - - # Force refresh of selection - self._curpage = -1 - self.SetSelection(sel_page) - - return True - - - def SetTabCtrlHeight(self, height): - """ - Sets the tab height. - - By default, the tab control height is calculated by measuring the text - height and bitmap sizes on the tab captions. - - Calling this method will override that calculation and set the tab control - to the specified height parameter. A call to this method will override - any call to :meth:`SetUniformBitmapSize`. Specifying -1 as the height will - return the control to its default auto-sizing behaviour. - - :param integer `height`: the tab control area height. - """ - - self._requested_tabctrl_height = height - - # if window is already initialized, recalculate the tab height - if self._dummy_wnd: - self.UpdateTabCtrlHeight() - - - def SetUniformBitmapSize(self, size): - """ - Ensures that all tabs will have the same height, even if some tabs don't have bitmaps. - Passing ``wx.DefaultSize`` to this method will instruct the control to use dynamic tab - height, which is the default behaviour. Under the default behaviour, when a tab with a - large bitmap is added, the tab control's height will automatically increase to accommodate - the larger bitmap. - - :param Size `size`: the tab bitmap size. - """ - - self._requested_bmp_size = wx.Size(*size) - - # if window is already initialized, recalculate the tab height - if self._dummy_wnd: - self.UpdateTabCtrlHeight() - - - def UpdateTabCtrlHeight(self, force=False): - """ - :meth:`UpdateTabCtrlHeight` does the actual tab resizing. It's meant - to be used interally. - - :param bool `force`: ``True`` to force the tab art to repaint. - """ - - # get the tab ctrl height we will use - height = self.CalculateTabCtrlHeight() - - # if the tab control height needs to change, update - # all of our tab controls with the new height - if self._tab_ctrl_height != height or force: - art = self._tabs.GetArtProvider() - - self._tab_ctrl_height = height - - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - - if pane.name == "dummy": - continue - - tab_frame = pane.window - tabctrl = tab_frame._tabs - tab_frame.SetTabCtrlHeight(self._tab_ctrl_height) - tabctrl.SetArtProvider(art.Clone()) - tab_frame.DoSizing() - - - def UpdateHintWindowSize(self): - """ Updates the :class:`~lib.agw.aui.framemanager.AuiManager` hint window size. """ - - size = self.CalculateNewSplitSize() - - # the placeholder hint window should be set to this size - info = self._mgr.GetPane("dummy") - - if info.IsOk(): - info.MinSize(size) - info.BestSize(size) - self._dummy_wnd.SetSize(size) - - - def CalculateNewSplitSize(self): - """ Calculates the size of the new split. """ - - # count number of tab controls - tab_ctrl_count = 0 - all_panes = self._mgr.GetAllPanes() - - for pane in all_panes: - if pane.name == "dummy": - continue - - tab_ctrl_count += 1 - - # if there is only one tab control, the first split - # should happen around the middle - if tab_ctrl_count < 2: - new_split_size = self.GetClientSize() - new_split_size.x /= 2 - new_split_size.y /= 2 - - else: - - # this is in place of a more complicated calculation - # that needs to be implemented - new_split_size = wx.Size(180, 180) - - return new_split_size - - - def CalculateTabCtrlHeight(self): - """ Calculates the tab control area height. """ - - # if a fixed tab ctrl height is specified, - # just return that instead of calculating a - # tab height - if self._requested_tabctrl_height != -1: - return self._requested_tabctrl_height - - # find out new best tab height - art = self._tabs.GetArtProvider() - - return art.GetBestTabCtrlSize(self, self._tabs.GetPages(), self._requested_bmp_size) - - - def GetArtProvider(self): - """ Returns the associated art provider. """ - - return self._tabs.GetArtProvider() - - - def SetAGWWindowStyleFlag(self, agwStyle): - """ - Sets the AGW-specific style of the window. - - :param integer `agwStyle`: the new window style. This can be a combination of the following bits: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook - ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet. - ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet. - ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook - ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab - ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging - ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control - ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width - ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed - ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available - ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar - ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab - ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs - ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close :class:`AuiNotebook` tabs by mouse middle button click - ``AUI_NB_SUB_NOTEBOOK`` This style is used by :class:`~lib.agw.aui.framemanager.AuiManager` to create automatic AuiNotebooks - ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present - ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows - ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items - ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser) - ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, - tabs cannot be dragged far enough outside of the notebook to become floating pages - ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default) - ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs - ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle - ==================================== ================================== - - :note: Please note that some styles cannot be changed after the window - creation and that `Refresh` might need to be be called after changing the - others for the change to take place immediately. - - .. todo:: Implementation of flags ``AUI_NB_RIGHT`` and ``AUI_NB_LEFT``. - """ - - self._agwFlags = agwStyle - - # if the control is already initialized - if self._mgr.GetManagedWindow() == self: - - # let all of the tab children know about the new style - - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - - tabframe = pane.window - tabctrl = tabframe._tabs - tabctrl.SetAGWFlags(self._agwFlags) - tabframe.DoSizing() - tabctrl.Refresh() - tabctrl.Update() - - - def GetAGWWindowStyleFlag(self): - """ - Returns the AGW-specific style of the window. - - :see: :meth:`SetAGWWindowStyleFlag` for a list of possible AGW-specific window styles. - """ - - return self._agwFlags - - - def AddPage(self, page, caption, select=False, bitmap=wx.NullBitmap, disabled_bitmap=wx.NullBitmap, control=None): - """ - Adds a page. If the `select` parameter is ``True``, calling this will generate a - page change event. - - :param Window `page`: the page to be added; - :param string `caption`: specifies the text for the new page; - :param bool `select`: specifies whether the page should be selected; - :param Bitmap `bitmap`: the bitmap to display in the enabled tab; - :param Bitmap `disabled_bitmap`: the bitmap to display in the disabled tab; - :param Window `control`: almost any :class:`Window` -derived instance to be located - inside a tab. - """ - - return self.InsertPage(self.GetPageCount(), page, caption, select, bitmap, disabled_bitmap, control) - - - def InsertPage(self, page_idx, page, caption, select=False, bitmap=wx.NullBitmap, disabled_bitmap=wx.NullBitmap, - control=None): - """ - This is similar to :meth:`AddPage`, but allows the ability to specify the insert location. - - :param integer `page_idx`: specifies the position for the new page; - :param Window `page`: the page to be added; - :param string `caption`: specifies the text for the new page; - :param bool `select`: specifies whether the page should be selected; - :param Bitmap `bitmap`: the bitmap to display in the enabled tab; - :param Bitmap `disabled_bitmap`: the bitmap to display in the disabled tab; - :param Window `control`: almost any :class:`Window` -derived instance to be located - inside a tab. - """ - - if not page: - return False - - page.Reparent(self) - info = AuiNotebookPage() - info.window = page - info.caption = caption - info.bitmap = bitmap - info.active = False - info.control = control - - originalPaneMgr = framemanager.GetManager(page) - if originalPaneMgr: - originalPane = originalPaneMgr.GetPane(page) - - if originalPane: - info.hasCloseButton = originalPane.HasCloseButton() - - if bitmap.IsOk() and not disabled_bitmap.IsOk(): - disabled_bitmap = MakeDisabledBitmap(bitmap) - - info.dis_bitmap = disabled_bitmap - - # if there are currently no tabs, the first added - # tab must be active - if self._tabs.GetPageCount() == 0: - info.active = True - - self._tabs.InsertPage(page, info, page_idx) - - # if that was the first page added, even if - # select is False, it must become the "current page" - # (though no select events will be fired) - if not select and self._tabs.GetPageCount() == 1: - select = True - - active_tabctrl = self.GetActiveTabCtrl() - if page_idx >= active_tabctrl.GetPageCount(): - active_tabctrl.AddPage(page, info) - else: - active_tabctrl.InsertPage(page, info, page_idx) - - force = False - if control: - force = True - control.Reparent(active_tabctrl) - control.Show() - - self.UpdateTabCtrlHeight(force=force) - self.DoSizing() - active_tabctrl.DoShowHide() - - # adjust selected index - if self._curpage >= page_idx: - self._curpage += 1 - - if select: - self.SetSelectionToWindow(page) - - return True - - - def DeletePage(self, page_idx): - """ - Deletes a page at the given index. Calling this method will generate a page - change event. - - :param integer `page_idx`: the page index to be deleted. - - :note: - - :meth:`DeletePage` removes a tab from the multi-notebook, and destroys the window as well. - - :see: :meth:`RemovePage` - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - wnd = self._tabs.GetWindowFromIdx(page_idx) - # hide the window in advance, as this will - # prevent flicker - wnd.Show(False) - - self.RemoveControlFromPage(page_idx) - - if not self.RemovePage(page_idx): - return False - - wnd.Destroy() - - return True - - - def RemovePage(self, page_idx): - """ - Removes a page, without deleting the window pointer. - - :param integer `page_idx`: the page index to be removed. - - :note: - - :meth:`RemovePage` removes a tab from the multi-notebook, but does not destroy the window. - - :see: :meth:`DeletePage` - """ - - # save active window pointer - active_wnd = None - if self._curpage >= 0: - active_wnd = self._tabs.GetWindowFromIdx(self._curpage) - - # save pointer of window being deleted - wnd = self._tabs.GetWindowFromIdx(page_idx) - new_active = None - - # make sure we found the page - if not wnd: - return False - - # find out which onscreen tab ctrl owns this tab - ctrl, ctrl_idx = self.FindTab(wnd) - if not ctrl: - return False - - currentPage = ctrl.GetPage(ctrl_idx) - is_curpage = (self._curpage == page_idx) - is_active_in_split = currentPage.active - - # remove the tab from main catalog - if not self._tabs.RemovePage(wnd): - return False - - # remove the tab from the onscreen tab ctrl - ctrl.RemovePage(wnd) - - if is_active_in_split: - - ctrl_new_page_count = ctrl.GetPageCount() - - if ctrl_idx >= ctrl_new_page_count: - ctrl_idx = ctrl_new_page_count - 1 - - if ctrl_idx >= 0 and ctrl_idx < ctrl.GetPageCount(): - - ctrl_idx = self.FindNextActiveTab(ctrl_idx, ctrl) - - # set new page as active in the tab split - ctrl.SetActivePage(ctrl_idx) - - # if the page deleted was the current page for the - # entire tab control, then record the window - # pointer of the new active page for activation - if is_curpage: - new_active = ctrl.GetWindowFromIdx(ctrl_idx) - - else: - - # we are not deleting the active page, so keep it the same - new_active = active_wnd - - if not new_active: - - # we haven't yet found a new page to active, - # so select the next page from the main tab - # catalogue - - if 0 <= page_idx < self._tabs.GetPageCount(): - new_active = self._tabs.GetPage(page_idx).window - if not new_active and self._tabs.GetPageCount() > 0: - new_active = self._tabs.GetPage(0).window - - self.RemoveEmptyTabFrames() - - # set new active pane - if new_active: - if not self.IsBeingDeleted(): - self._curpage = -1 - self.SetSelectionToWindow(new_active) - else: - self._curpage = -1 - self._tabs.SetNoneActive() - - return True - - - def FindNextActiveTab(self, ctrl_idx, ctrl): - """ - Finds the next active tab (used mainly when :class:`AuiNotebook` has inactive/disabled - tabs in it). - - :param integer `ctrl_idx`: the index of the first (most obvious) tab to check for active status; - :param `ctrl`: an instance of :class:`AuiTabCtrl`. - """ - - if self.GetEnabled(ctrl_idx): - return ctrl_idx - - for indx in xrange(ctrl_idx, ctrl.GetPageCount()): - if self.GetEnabled(indx): - return indx - - for indx in xrange(ctrl_idx, -1, -1): - if self.GetEnabled(indx): - return indx - - return 0 - - - def HideAllTabs(self, hidden=True): - """ - Hides all tabs on the :class:`AuiNotebook` control. - - :param bool `hidden`: if ``True`` hides all tabs. - """ - - self._hide_tabs = hidden - - - def SetSashDClickUnsplit(self, unsplit=True): - """ - Sets whether to unsplit a splitted :class:`AuiNotebook` when double-clicking on a sash. - - :param bool `unsplit`: ``True`` to unsplit on sash double-clicking, ``False`` otherwise. - """ - - self._sash_dclick_unsplit = unsplit - - - def GetSashDClickUnsplit(self): - """ - Returns whether a splitted :class:`AuiNotebook` can be unsplitted by double-clicking - on the splitter sash. - """ - - return self._sash_dclick_unsplit - - - def SetMinMaxTabWidth(self, minTabWidth, maxTabWidth): - """ - Sets the minimum and/or the maximum tab widths for :class:`AuiNotebook` when the - ``AUI_NB_TAB_FIXED_WIDTH`` style is defined. - - Pass -1 to either `minTabWidth` or `maxTabWidth` to reset to the default tab - width behaviour for :class:`AuiNotebook`. - - :param integer `minTabWidth`: the minimum allowed tab width, in pixels; - :param integer `maxTabWidth`: the maximum allowed tab width, in pixels. - - :note: Minimum and maximum tabs widths are used only when the ``AUI_NB_TAB_FIXED_WIDTH`` - style is present. - """ - - if minTabWidth > maxTabWidth: - raise Exception("Minimum tab width must be less or equal than maximum tab width") - - self._tabBounds = (minTabWidth, maxTabWidth) - self.SetAGWWindowStyleFlag(self._agwFlags) - - - def GetMinMaxTabWidth(self): - """ - Returns the minimum and the maximum tab widths for :class:`AuiNotebook` when the - ``AUI_NB_TAB_FIXED_WIDTH`` style is defined. - - :note: Minimum and maximum tabs widths are used only when the ``AUI_NB_TAB_FIXED_WIDTH`` - style is present. - - :see: :meth:`SetMinMaxTabWidth` for more information. - """ - - return self._tabBounds - - - def GetPageIndex(self, page_wnd): - """ - Returns the page index for the specified window. If the window is not - found in the notebook, ``wx.NOT_FOUND`` is returned. - - :param Window `page_wnd`: the window we are looking for. - """ - - return self._tabs.GetIdxFromWindow(page_wnd) - - - def SetPageText(self, page_idx, text): - """ - Sets the tab label for the page. - - :param integer `page_idx`: the page index; - :param string `text`: the new tab label. - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - # update our own tab catalog - page_info = self._tabs.GetPage(page_idx) - should_refresh = page_info.caption != text - page_info.caption = text - - # update what's on screen - ctrl, ctrl_idx = self.FindTab(page_info.window) - if not ctrl: - return False - - info = ctrl.GetPage(ctrl_idx) - should_refresh = should_refresh or info.caption != text - info.caption = text - - if should_refresh: - ctrl.Refresh() - ctrl.Update() - - self.UpdateTabCtrlHeight(force=True) - - return True - - - def GetPageText(self, page_idx): - """ - Returns the tab label for the page. - - :param integer `page_idx`: the page index. - """ - - if page_idx >= self._tabs.GetPageCount(): - return "" - - # update our own tab catalog - page_info = self._tabs.GetPage(page_idx) - return page_info.caption - - - def SetPageBitmap(self, page_idx, bitmap): - """ - Sets the tab bitmap for the page. - - :param integer `page_idx`: the page index; - :param Bitmap `bitmap`: the bitmap to display on the page tab. - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - # update our own tab catalog - page_info = self._tabs.GetPage(page_idx) - should_refresh = page_info.bitmap is not bitmap - page_info.bitmap = bitmap - if bitmap.IsOk() and not page_info.dis_bitmap.IsOk(): - page_info.dis_bitmap = MakeDisabledBitmap(bitmap) - - # tab height might have changed - self.UpdateTabCtrlHeight() - - # update what's on screen - ctrl, ctrl_idx = self.FindTab(page_info.window) - if not ctrl: - return False - - info = ctrl.GetPage(ctrl_idx) - should_refresh = should_refresh or info.bitmap is not bitmap - info.bitmap = bitmap - info.dis_bitmap = page_info.dis_bitmap - if should_refresh: - ctrl.Refresh() - ctrl.Update() - - return True - - - def GetPageBitmap(self, page_idx): - """ - Returns the tab bitmap for the page. - - :param integer `page_idx`: the page index. - """ - - if page_idx >= self._tabs.GetPageCount(): - return wx.NullBitmap - - # update our own tab catalog - page_info = self._tabs.GetPage(page_idx) - return page_info.bitmap - - - def SetImageList(self, imageList): - """ - Sets the image list for the :class:`AuiNotebook` control. - - :param ImageList `imageList`: the bitmap image list to associate to :class:`AuiNotebook`. - """ - - self._imageList = imageList - - - def AssignImageList(self, imageList): - """ - Sets the image list for the :class:`AuiNotebook` control. - - :param `imageList`: an instance of :class:`ImageList`. - """ - - self.SetImageList(imageList) - - - def GetImageList(self): - """ Returns the associated image list (if any). """ - - return self._imageList - - - def SetPageImage(self, page, image): - """ - Sets the image index for the given page. - - :param integer `page`: the page index; - :param integer `image`: an index into the image list which was set with :meth:`SetImageList`. - """ - - if page >= self._tabs.GetPageCount(): - return False - - if not isinstance(image, types.IntType): - raise Exception("The image parameter must be an integer, you passed " \ - "%s"%repr(image)) - - if not self._imageList: - raise Exception("To use SetPageImage you need to associate an image list " \ - "Using SetImageList or AssignImageList") - - if image >= self._imageList.GetImageCount(): - raise Exception("Invalid image index (%d), the image list contains only" \ - " (%d) bitmaps"%(image, self._imageList.GetImageCount())) - - if image == -1: - self.SetPageBitmap(page, wx.NullBitmap) - return - - bitmap = self._imageList.GetBitmap(image) - self.SetPageBitmap(page, bitmap) - - - def GetPageImage(self, page): - """ - Returns the image index for the given page. - - :param integer `page`: the given page for which to retrieve the image index. - """ - - if page >= self._tabs.GetPageCount(): - return wx.NOT_FOUND - - bitmap = self.GetPageBitmap(page) - bmpData1 = bitmap.ConvertToImage().GetData() - - for indx in xrange(self._imageList.GetImageCount()): - imgListBmp = self._imageList.GetBitmap(indx) - bmpData2 = imgListBmp.ConvertToImage().GetData() - if bmpData1 == bmpData2: - return indx - - return wx.NOT_FOUND - - - def SetPageTextColour(self, page_idx, colour): - """ - Sets the tab text colour for the page. - - :param integer `page_idx`: the page index; - :param Colour `colour`: the new tab label text colour. - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - # update our own tab catalog - page_info = self._tabs.GetPage(page_idx) - should_refresh = page_info.text_colour != colour - page_info.text_colour = colour - - # update what's on screen - ctrl, ctrl_idx = self.FindTab(page_info.window) - if not ctrl: - return False - - info = ctrl.GetPage(ctrl_idx) - should_refresh = should_refresh or info.text_colour != colour - info.text_colour = page_info.text_colour - - if should_refresh: - ctrl.Refresh() - ctrl.Update() - - return True - - - def GetPageTextColour(self, page_idx): - """ - Returns the tab text colour for the page. - - :param integer `page_idx`: the page index. - """ - - if page_idx >= self._tabs.GetPageCount(): - return wx.NullColour - - # update our own tab catalog - page_info = self._tabs.GetPage(page_idx) - return page_info.text_colour - - - def AddControlToPage(self, page_idx, control): - """ - Adds a control inside a tab (not in the tab area). - - :param integer `page_idx`: the page index; - :param Window `control`: almost any :class:`Window` -derived instance to be located - inside a tab. - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - # update our own tab catalog - page_info = self._tabs.GetPage(page_idx) - page_info.control = control - - # tab height might have changed - self.UpdateTabCtrlHeight(force=True) - - # update what's on screen - ctrl, ctrl_idx = self.FindTab(page_info.window) - if not ctrl: - return False - - control.Reparent(ctrl) - - info = ctrl.GetPage(ctrl_idx) - info.control = control - ctrl.Refresh() - ctrl.Update() - - return True - - - def RemoveControlFromPage(self, page_idx): - """ - Removes a control from a tab (not from the tab area). - - :param integer `page_idx`: the page index. - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - page_info = self._tabs.GetPage(page_idx) - if page_info.control is None: - return False - - page_info.control.Destroy() - page_info.control = None - - # tab height might have changed - self.UpdateTabCtrlHeight(force=True) - - # update what's on screen - ctrl, ctrl_idx = self.FindTab(page_info.window) - if not ctrl: - return False - - info = ctrl.GetPage(ctrl_idx) - info.control = None - ctrl.Refresh() - ctrl.Update() - - return True - - - def SetCloseButton(self, page_idx, hasCloseButton): - """ - Sets whether a tab should display a close button or not. - - :param integer `page_idx`: the page index; - :param bool `hasCloseButton`: ``True`` if the page displays a close button. - - :note: This can only be called if ``AUI_NB_CLOSE_ON_ALL_TABS`` is specified. - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - # There's really not a need for this exception. If the close on - # all tabs is False, no close buttons get drawn. - #if self._agwFlags & AUI_NB_CLOSE_ON_ALL_TABS == 0: - # raise Exception("SetCloseButton can only be used with AUI_NB_CLOSE_ON_ALL_TABS style.") - - # update our own tab catalog - page_info = self._tabs.GetPage(page_idx) - page_info.hasCloseButton = hasCloseButton - - # update what's on screen - ctrl, ctrl_idx = self.FindTab(page_info.window) - if not ctrl: - return False - - info = ctrl.GetPage(ctrl_idx) - info.hasCloseButton = page_info.hasCloseButton - ctrl.Refresh() - ctrl.Update() - - return True - - - def HasCloseButton(self, page_idx): - """ - Returns whether a tab displays a close button or not. - - :param integer `page_idx`: the page index. - - :note: This can only be called if ``AUI_NB_CLOSE_ON_ALL_TABS`` is specified. - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - page_info = self._tabs.GetPage(page_idx) - return page_info.hasCloseButton - - - def GetSelection(self): - """ Returns the index of the currently active page, or -1 if none was selected. """ - - return self._curpage - - - def GetCurrentPage(self): - """ Returns the currently active page (not the index), or ``None`` if none was selected. """ - - if self._curpage >= 0 and self._curpage < self._tabs.GetPageCount(): - return self.GetPage(self._curpage) - - return None - - - def EnsureVisible(self, indx): - """ - Ensures the input page index `indx` is visible. - - :param integer `indx`: the page index. - """ - - self._tabs.MakeTabVisible(indx, self) - - - def SetSelection(self, new_page, force=False): - """ - Sets the page selection. Calling this method will generate a page change event. - - :param integer `new_page`: the index of the new selection; - :param bool `force`: whether to force the selection or not. - """ - wnd = self._tabs.GetWindowFromIdx(new_page) - - #Update page access time - self._tabs.GetPages()[new_page].access_time = datetime.datetime.now() - - if not wnd or not self.GetEnabled(new_page): - return self._curpage - - # don't change the page unless necessary - # however, clicking again on a tab should give it the focus. - if new_page == self._curpage and not force: - - ctrl, ctrl_idx = self.FindTab(wnd) - if wx.Window.FindFocus() != ctrl: - ctrl.SetFocus() - - return self._curpage - - evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, self.GetId()) - evt.SetSelection(new_page) - evt.SetOldSelection(self._curpage) - evt.SetEventObject(self) - - if not self.GetEventHandler().ProcessEvent(evt) or evt.IsAllowed(): - - old_curpage = self._curpage - self._curpage = new_page - - # program allows the page change - evt.SetEventType(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED) - self.GetEventHandler().ProcessEvent(evt) - - if not evt.IsAllowed(): # event is no longer allowed after handler - return self._curpage - - ctrl, ctrl_idx = self.FindTab(wnd) - - if ctrl: - self._tabs.SetActivePage(wnd) - ctrl.SetActivePage(ctrl_idx) - self.DoSizing() - ctrl.DoShowHide() - ctrl.MakeTabVisible(ctrl_idx, ctrl) - - # set fonts - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - - tabctrl = pane.window._tabs - if tabctrl != ctrl: - tabctrl.SetSelectedFont(self._normal_font) - else: - tabctrl.SetSelectedFont(self._selected_font) - - tabctrl.Refresh() - tabctrl.Update() - - # Set the focus to the page if we're not currently focused on the tab. - # This is Firefox-like behaviour. - if wnd.IsShownOnScreen() and wx.Window.FindFocus() != ctrl: - wnd.SetFocus() - - return old_curpage - - return self._curpage - - - def SetSelectionToWindow(self, win): - """ - Sets the selection based on the input window `win`. - - :param `win`: a :class:`Window` derived window. - """ - - idx = self._tabs.GetIdxFromWindow(win) - - if idx == wx.NOT_FOUND: - raise Exception("invalid notebook page") - - if not self.GetEnabled(idx): - return - - # since a tab was clicked, let the parent know that we received - # the focus, even if we will assign that focus immediately - # to the child tab in the SetSelection call below - # (the child focus event will also let AuiManager, if any, - # know that the notebook control has been activated) - - parent = self.GetParent() - if parent: - eventFocus = wx.ChildFocusEvent(self) - parent.GetEventHandler().ProcessEvent(eventFocus) - - self.SetSelection(idx) - - - def SetSelectionToPage(self, page): - """ - Sets the selection based on the input page. - - :param `page`: an instance of :class:`AuiNotebookPage`. - """ - - self.SetSelectionToWindow(page.window) - - - def GetPageCount(self): - """ Returns the number of pages in the notebook. """ - - return self._tabs.GetPageCount() - - - def GetPage(self, page_idx): - """ - Returns the page specified by the given index. - - :param integer `page_idx`: the page index. - """ - - if page_idx >= self._tabs.GetPageCount(): - raise Exception("invalid notebook page") - - return self._tabs.GetWindowFromIdx(page_idx) - - - def GetPageInfo(self, page_idx): - """ - Returns the :class:`AuiNotebookPage` info structure specified by the given index. - - :param integer `page_idx`: the page index. - """ - - if page_idx >= self._tabs.GetPageCount(): - raise Exception("invalid notebook page") - - return self._tabs.GetPage(page_idx) - - - def GetEnabled(self, page_idx): - """ - Returns whether the page specified by the index `page_idx` is enabled. - - :param integer `page_idx`: the page index. - """ - - return self._tabs.GetEnabled(page_idx) - - - def EnableTab(self, page_idx, enable=True): - """ - Enables/disables a page in the notebook. - - :param integer `page_idx`: the page index; - :param bool `enable`: ``True`` to enable the page, ``False`` to disable it. - """ - - self._tabs.EnableTab(page_idx, enable) - self.Refresh() - - - def DoSizing(self): - """ Performs all sizing operations in each tab control. """ - - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - - tabframe = pane.window - tabframe.DoSizing() - - - def GetAuiManager(self): - """ Returns the associated :class:`~lib.agw.aui.framemanager.AuiManager`. """ - - return self._mgr - - - def GetActiveTabCtrl(self): - """ - Returns the active tab control. It is called to determine which control - gets new windows being added. - """ - - if self._curpage >= 0 and self._curpage < self._tabs.GetPageCount(): - - # find the tab ctrl with the current page - ctrl, idx = self.FindTab(self._tabs.GetPage(self._curpage).window) - if ctrl: - return ctrl - - # no current page, just find the first tab ctrl - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - - tabframe = pane.window - return tabframe._tabs - - # If there is no tabframe at all, create one - tabframe = TabFrame(self) - tabframe.SetTabCtrlHeight(self._tab_ctrl_height) - self._tab_id_counter += 1 - tabframe._tabs = AuiTabCtrl(self, self._tab_id_counter) - - tabframe._tabs.SetAGWFlags(self._agwFlags) - tabframe._tabs.SetArtProvider(self._tabs.GetArtProvider().Clone()) - self._mgr.AddPane(tabframe, framemanager.AuiPaneInfo().Center().CaptionVisible(False). - PaneBorder((self._agwFlags & AUI_NB_SUB_NOTEBOOK) == 0)) - - self._mgr.Update() - - return tabframe._tabs - - - def FindTab(self, page): - """ - Finds the tab control that currently contains the window as well - as the index of the window in the tab control. It returns ``True`` if the - window was found, otherwise ``False``. - - :param `page`: an instance of :class:`AuiNotebookPage`. - """ - - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - - tabframe = pane.window - - page_idx = tabframe._tabs.GetIdxFromWindow(page) - - if page_idx != -1: - - ctrl = tabframe._tabs - idx = page_idx - return ctrl, idx - - return None, wx.NOT_FOUND - - - def Split(self, page, direction): - """ - Performs a split operation programmatically. - - :param integer `page`: indicates the page that will be split off. This page will also become - the active page after the split. - :param integer `direction`: specifies where the pane should go, it should be one of the - following: ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, or ``wx.RIGHT``. - """ - - cli_size = self.GetClientSize() - - # get the page's window pointer - wnd = self.GetPage(page) - if not wnd: - return - - # notebooks with 1 or less pages can't be split - if self.GetPageCount() < 2: - return - - # find out which tab control the page currently belongs to - - src_tabs, src_idx = self.FindTab(wnd) - if not src_tabs: - return - - selection = self.GetSelection() - - # choose a split size - if self.GetPageCount() > 2: - split_size = self.CalculateNewSplitSize() - else: - # because there are two panes, always split them - # equally - split_size = self.GetClientSize() - split_size.x /= 2 - split_size.y /= 2 - - # create a new tab frame - new_tabs = TabFrame(self) - new_tabs._rect = wx.RectPS(wx.Point(0, 0), split_size) - new_tabs.SetTabCtrlHeight(self._tab_ctrl_height) - self._tab_id_counter += 1 - new_tabs._tabs = AuiTabCtrl(self, self._tab_id_counter) - - new_tabs._tabs.SetArtProvider(self._tabs.GetArtProvider().Clone()) - new_tabs._tabs.SetAGWFlags(self._agwFlags) - dest_tabs = new_tabs._tabs - - page_info = src_tabs.GetPage(src_idx) - if page_info.control: - self.ReparentControl(page_info.control, dest_tabs) - - cloned_buttons = self.CloneTabAreaButtons() - for clone in cloned_buttons: - dest_tabs.AddButton(clone.id, clone.location, clone.bitmap, clone.dis_bitmap) - # create a pane info structure with the information - # about where the pane should be added - pane_info = framemanager.AuiPaneInfo().Bottom().CaptionVisible(False) - - if direction == wx.LEFT: - - pane_info.Left() - mouse_pt = wx.Point(0, cli_size.y/2) - - elif direction == wx.RIGHT: - - pane_info.Right() - mouse_pt = wx.Point(cli_size.x, cli_size.y/2) - - elif direction == wx.TOP: - - pane_info.Top() - mouse_pt = wx.Point(cli_size.x/2, 0) - - elif direction == wx.BOTTOM: - - pane_info.Bottom() - mouse_pt = wx.Point(cli_size.x/2, cli_size.y) - - self._mgr.AddPane(new_tabs, pane_info, mouse_pt) - self._mgr.Update() - - # remove the page from the source tabs - page_info.active = False - - src_tabs.RemovePage(page_info.window) - - if src_tabs.GetPageCount() > 0: - if selection < 0 or selection == src_idx: - active_page = 0 - else: - if selection > src_idx: - selection -= 1 - - active_page = selection - - src_tabs.SetActivePage(active_page) - src_tabs.DoShowHide() - src_tabs.Refresh() - - # add the page to the destination tabs - dest_tabs.InsertPage(page_info.window, page_info, 0) - - if src_tabs.GetPageCount() == 0: - self.RemoveEmptyTabFrames() - - self.DoSizing() - dest_tabs.DoShowHide() - dest_tabs.Refresh() - - # force the set selection function reset the selection - self._curpage = -1 - - # set the active page to the one we just split off - self.SetSelectionToPage(page_info) - - self.UpdateHintWindowSize() - - - def UnSplit(self): - """ Restores original view after a tab split. """ - - self.Freeze() - - # remember the tab now selected - nowSelected = self.GetSelection() - # select first tab as destination - self.SetSelection(0) - # iterate all other tabs - for idx in xrange(1, self.GetPageCount()): - # get win reference - win = self.GetPage(idx) - # get tab title - title = self.GetPageText(idx) - # get page bitmap - bmp = self.GetPageBitmap(idx) - # remove from notebook - self.RemovePage(idx) - # re-add in the same position so it will tab - self.InsertPage(idx, win, title, False, bmp) - # restore orignial selected tab - self.SetSelection(nowSelected) - - self.Thaw() - - - def ReparentControl(self, control, dest_tabs): - """ - Reparents a control added inside a tab. - - :param Window `control`: almost any :class:`Window` -derived instance to be located - inside a tab; - :param `dest_tabs`: the destination :class:`AuiTabCtrl`. - """ - - control.Hide() - control.Reparent(dest_tabs) - - - def UnsplitDClick(self, part, sash_size, pos): - """ - Unsplit the :class:`AuiNotebook` on sash double-click. - - :param `part`: an UI part representing the sash; - :param integer `sash_size`: the sash size; - :param Point `pos`: the double-click mouse position. - - .. warning:: - - Due to a bug on MSW, for disabled pages :func:`FindWindowAtPoint` - returns the wrong window. See http://trac.wxwidgets.org/ticket/2942 - - """ - - if not self._sash_dclick_unsplit: - # Unsplit not allowed - return - - pos1 = wx.Point(*pos) - pos2 = wx.Point(*pos) - if part.orientation == wx.HORIZONTAL: - pos1.y -= 2*sash_size - pos2.y += 2*sash_size + self.GetTabCtrlHeight() - elif part.orientation == wx.VERTICAL: - pos1.x -= 2*sash_size - pos2.x += 2*sash_size - else: - raise Exception("Invalid UI part orientation") - - pos1, pos2 = self.ClientToScreen(pos1), self.ClientToScreen(pos2) - win1, win2 = wx.FindWindowAtPoint(pos1), wx.FindWindowAtPoint(pos2) - - if isinstance(win1, wx.ScrollBar): - # Hopefully it will work - pos1 = wx.Point(*pos) - shift = wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X) + 2*(sash_size+1) - if part.orientation == wx.HORIZONTAL: - pos1.y -= shift - else: - pos1.x -= shift - - pos1 = self.ClientToScreen(pos1) - win1 = wx.FindWindowAtPoint(pos1) - - if isinstance(win2, wx.ScrollBar): - pos2 = wx.Point(*pos) - shift = wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X) + 2*(sash_size+1) - if part.orientation == wx.HORIZONTAL: - pos2.y += shift - else: - pos2.x += shift - - pos2 = self.ClientToScreen(pos2) - win2 = wx.FindWindowAtPoint(pos2) - - if not win1 or not win2: - # How did we get here? - return - - if isinstance(win1, AuiNotebook) or isinstance(win2, AuiNotebook): - # This is a bug on MSW, for disabled pages wx.FindWindowAtPoint - # returns the wrong window. - # See http://trac.wxwidgets.org/ticket/2942 - return - - tab_frame1, tab_frame2 = self.GetTabFrameFromWindow(win1), self.GetTabFrameFromWindow(win2) - - if not tab_frame1 or not tab_frame2: - return - - tab_ctrl_1, tab_ctrl_2 = tab_frame1._tabs, tab_frame2._tabs - - if tab_ctrl_1.GetPageCount() > tab_ctrl_2.GetPageCount(): - src_tabs = tab_ctrl_2 - dest_tabs = tab_ctrl_1 - else: - src_tabs = tab_ctrl_1 - dest_tabs = tab_ctrl_2 - - selection = -1 - page_count = dest_tabs.GetPageCount() - - for page in xrange(src_tabs.GetPageCount()-1, -1, -1): - # remove the page from the source tabs - page_info = src_tabs.GetPage(page) - if page_info.active: - selection = page_count + page - src_tabs.RemovePage(page_info.window) - - # add the page to the destination tabs - dest_tabs.AddPage(page_info.window, page_info) - if page_info.control: - self.ReparentControl(page_info.control, dest_tabs) - - self.RemoveEmptyTabFrames() - - dest_tabs.DoShowHide() - self.DoSizing() - dest_tabs.Refresh() - self._mgr.Update() - if selection > 0: - wx.CallAfter(dest_tabs.MakeTabVisible, selection, self) - - - def OnSize(self, event): - """ - Handles the ``wx.EVT_SIZE`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`SizeEvent` event to be processed. - """ - - self.UpdateHintWindowSize() - event.Skip() - - - def OnTabClicked(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_PAGE_CHANGING`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - if self._textCtrl is not None: - self._textCtrl.StopEditing() - - ctrl = event.GetEventObject() - assert ctrl != None - - wnd = ctrl.GetWindowFromIdx(event.GetSelection()) - assert wnd != None - - self.SetSelectionToWindow(wnd) - - - def OnTabBgDClick(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_BG_DCLICK`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - if self._textCtrl is not None: - self._textCtrl.StopEditing() - - # notify owner that the tabbar background has been double-clicked - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, self.GetId()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def OnTabDClick(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_TAB_DCLICK`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - # notify owner that the tabbar background has been double-clicked - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_DCLICK, self.GetId()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - tabs = event.GetEventObject() - if not tabs.GetEnabled(event.GetSelection()): - return - - if not self.IsRenamable(event.GetSelection()): - return - - self.EditTab(event.GetSelection()) - - - def OnTabBeginDrag(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_BEGIN_DRAG`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - tabs = event.GetEventObject() - if not tabs.GetEnabled(event.GetSelection()): - return - - self._last_drag_x = 0 - - - def OnTabDragMotion(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_DRAG_MOTION`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - self._curpage = event.GetSelection() - - tabs = event.GetEventObject() - if not tabs.GetEnabled(event.GetSelection()): - return - - if self._textCtrl is not None: - self._textCtrl.StopEditing() - - screen_pt = wx.GetMousePosition() - client_pt = self.ScreenToClient(screen_pt) - zero = wx.Point(0, 0) - - src_tabs = event.GetEventObject() - dest_tabs = self.GetTabCtrlFromPoint(client_pt) - - if dest_tabs == src_tabs: - - # always hide the hint for inner-tabctrl drag - self._mgr.HideHint() - - # if tab moving is not allowed, leave - if not self._agwFlags & AUI_NB_TAB_MOVE: - return - - pt = dest_tabs.ScreenToClient(screen_pt) - - # this is an inner-tab drag/reposition - dest_location_tab = dest_tabs.TabHitTest(pt.x, pt.y) - - if dest_location_tab: - - src_idx = event.GetSelection() - dest_idx = dest_tabs.GetIdxFromWindow(dest_location_tab) - - # prevent jumpy drag - if (src_idx == dest_idx) or dest_idx == -1 or \ - (src_idx > dest_idx and self._last_drag_x <= pt.x) or \ - (src_idx < dest_idx and self._last_drag_x >= pt.x): - - self._last_drag_x = pt.x - return - - src_tab = dest_tabs.GetWindowFromIdx(src_idx) - dest_tabs.MovePage(src_tab, dest_idx) - self._tabs.MovePage(self._tabs.GetPage(src_idx).window, dest_idx) - dest_tabs.SetActivePage(dest_idx) - dest_tabs.DoShowHide() - dest_tabs.Refresh() - self._last_drag_x = pt.x - - return - - # if external drag is allowed, check if the tab is being dragged - # over a different AuiNotebook control - if self._agwFlags & AUI_NB_TAB_EXTERNAL_MOVE: - - tab_ctrl = wx.FindWindowAtPoint(screen_pt) - - # if we aren't over any window, stop here - if not tab_ctrl: - if self._agwFlags & AUI_NB_TAB_FLOAT: - if self.IsMouseWellOutsideWindow(): - hintRect = wx.RectPS(screen_pt, (400, 300)) - # Use CallAfter so we overwrite the hint that might be - # shown by our superclass: - wx.CallAfter(self._mgr.ShowHint, hintRect) - return - - # make sure we are not over the hint window - if not isinstance(tab_ctrl, wx.Frame): - while tab_ctrl: - if isinstance(tab_ctrl, AuiTabCtrl): - break - - tab_ctrl = tab_ctrl.GetParent() - - if tab_ctrl: - nb = tab_ctrl.GetParent() - - if nb != self: - - hint_rect = tab_ctrl.GetClientRect() - hint_rect.x, hint_rect.y = tab_ctrl.ClientToScreenXY(hint_rect.x, hint_rect.y) - self._mgr.ShowHint(hint_rect) - return - - else: - - if not dest_tabs: - # we are either over a hint window, or not over a tab - # window, and there is no where to drag to, so exit - return - - if self._agwFlags & AUI_NB_TAB_FLOAT: - if self.IsMouseWellOutsideWindow(): - hintRect = wx.RectPS(screen_pt, (400, 300)) - # Use CallAfter so we overwrite the hint that might be - # shown by our superclass: - wx.CallAfter(self._mgr.ShowHint, hintRect) - return - - # if there are less than two panes, split can't happen, so leave - if self._tabs.GetPageCount() < 2: - return - - # if tab moving is not allowed, leave - if not self._agwFlags & AUI_NB_TAB_SPLIT: - return - - if dest_tabs: - - hint_rect = dest_tabs.GetRect() - hint_rect.x, hint_rect.y = self.ClientToScreenXY(hint_rect.x, hint_rect.y) - self._mgr.ShowHint(hint_rect) - - else: - rect = self._mgr.CalculateHintRect(self._dummy_wnd, client_pt, zero) - if rect.IsEmpty(): - self._mgr.HideHint() - return - - hit_wnd = wx.FindWindowAtPoint(screen_pt) - if hit_wnd and not isinstance(hit_wnd, AuiNotebook): - tab_frame = self.GetTabFrameFromWindow(hit_wnd) - if tab_frame: - hint_rect = wx.Rect(*tab_frame._rect) - hint_rect.x, hint_rect.y = self.ClientToScreenXY(hint_rect.x, hint_rect.y) - rect.Intersect(hint_rect) - self._mgr.ShowHint(rect) - else: - self._mgr.DrawHintRect(self._dummy_wnd, client_pt, zero) - else: - self._mgr.DrawHintRect(self._dummy_wnd, client_pt, zero) - - - def OnTabEndDrag(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_END_DRAG`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - tabs = event.GetEventObject() - if not tabs.GetEnabled(event.GetSelection()): - return - - self._mgr.HideHint() - - src_tabs = event.GetEventObject() - if not src_tabs: - raise Exception("no source object?") - - # get the mouse position, which will be used to determine the drop point - mouse_screen_pt = wx.GetMousePosition() - mouse_client_pt = self.ScreenToClient(mouse_screen_pt) - - # check for an external move - if self._agwFlags & AUI_NB_TAB_EXTERNAL_MOVE: - tab_ctrl = wx.FindWindowAtPoint(mouse_screen_pt) - - while tab_ctrl: - - if isinstance(tab_ctrl, AuiTabCtrl): - break - - tab_ctrl = tab_ctrl.GetParent() - - if tab_ctrl: - - nb = tab_ctrl.GetParent() - - if nb != self: - - # find out from the destination control - # if it's ok to drop this tab here - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, self.GetId()) - e.SetSelection(event.GetSelection()) - e.SetOldSelection(event.GetSelection()) - e.SetEventObject(self) - e.SetDragSource(self) - e.Veto() # dropping must be explicitly approved by control owner - - nb.GetEventHandler().ProcessEvent(e) - - if not e.IsAllowed(): - - # no answer or negative answer - self._mgr.HideHint() - return - - # drop was allowed - src_idx = event.GetSelection() - src_page = src_tabs.GetWindowFromIdx(src_idx) - - # Check that it's not an impossible parent relationship - p = nb - while p and not p.IsTopLevel(): - if p == src_page: - return - - p = p.GetParent() - - # get main index of the page - main_idx = self._tabs.GetIdxFromWindow(src_page) - if main_idx == wx.NOT_FOUND: - raise Exception("no source page?") - - # make a copy of the page info - page_info = self._tabs.GetPage(main_idx) - - # remove the page from the source notebook - self.RemovePage(main_idx) - - # reparent the page - src_page.Reparent(nb) - - # Reparent the control in a tab (if any) - if page_info.control: - self.ReparentControl(page_info.control, tab_ctrl) - - # find out the insert idx - dest_tabs = tab_ctrl - pt = dest_tabs.ScreenToClient(mouse_screen_pt) - - target = dest_tabs.TabHitTest(pt.x, pt.y) - insert_idx = -1 - if target: - insert_idx = dest_tabs.GetIdxFromWindow(target) - - # add the page to the new notebook - if insert_idx == -1: - insert_idx = dest_tabs.GetPageCount() - - dest_tabs.InsertPage(page_info.window, page_info, insert_idx) - nb._tabs.AddPage(page_info.window, page_info) - - nb.DoSizing() - dest_tabs.DoShowHide() - dest_tabs.Refresh() - - # set the selection in the destination tab control - nb.SetSelectionToPage(page_info) - - # notify owner that the tab has been dragged - e2 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, self.GetId()) - e2.SetSelection(event.GetSelection()) - e2.SetOldSelection(event.GetSelection()) - e2.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e2) - - # notify the target notebook that the tab has been dragged - e3 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, nb.GetId()) - e3.SetSelection(insert_idx) - e3.SetOldSelection(insert_idx) - e3.SetEventObject(nb) - nb.GetEventHandler().ProcessEvent(e3) - - return - - if self._agwFlags & AUI_NB_TAB_FLOAT: - self._mgr.HideHint() - if self.IsMouseWellOutsideWindow(): - # Use CallAfter so we our superclass can deal with the event first - wx.CallAfter(self.FloatPage, self.GetSelection()) - event.Skip() - return - - # only perform a tab split if it's allowed - dest_tabs = None - - if self._agwFlags & AUI_NB_TAB_SPLIT and self._tabs.GetPageCount() >= 2: - - # If the pointer is in an existing tab frame, do a tab insert - hit_wnd = wx.FindWindowAtPoint(mouse_screen_pt) - tab_frame = self.GetTabFrameFromTabCtrl(hit_wnd) - insert_idx = -1 - - if tab_frame: - - dest_tabs = tab_frame._tabs - - if dest_tabs == src_tabs: - return - - pt = dest_tabs.ScreenToClient(mouse_screen_pt) - target = dest_tabs.TabHitTest(pt.x, pt.y) - - if target: - insert_idx = dest_tabs.GetIdxFromWindow(target) - - else: - - zero = wx.Point(0, 0) - rect = self._mgr.CalculateHintRect(self._dummy_wnd, mouse_client_pt, zero) - - if rect.IsEmpty(): - # there is no suitable drop location here, exit out - return - - # If there is no tabframe at all, create one - new_tabs = TabFrame(self) - new_tabs._rect = wx.RectPS(wx.Point(0, 0), self.CalculateNewSplitSize()) - new_tabs.SetTabCtrlHeight(self._tab_ctrl_height) - self._tab_id_counter += 1 - new_tabs._tabs = AuiTabCtrl(self, self._tab_id_counter) - new_tabs._tabs.SetArtProvider(self._tabs.GetArtProvider().Clone()) - new_tabs._tabs.SetAGWFlags(self._agwFlags) - - self._mgr.AddPane(new_tabs, framemanager.AuiPaneInfo().Bottom().CaptionVisible(False), mouse_client_pt) - self._mgr.Update() - dest_tabs = new_tabs._tabs - - cloned_buttons = self.CloneTabAreaButtons() - for clone in cloned_buttons: - dest_tabs.AddButton(clone.id, clone.location, clone.bitmap, clone.dis_bitmap) - # remove the page from the source tabs - page_info = src_tabs.GetPage(event.GetSelection()) - - if page_info.control: - self.ReparentControl(page_info.control, dest_tabs) - - page_info.active = False - src_tabs.RemovePage(page_info.window) - - if src_tabs.GetPageCount() > 0: - src_tabs.SetActivePage(0) - src_tabs.DoShowHide() - src_tabs.Refresh() - - # add the page to the destination tabs - if insert_idx == -1: - insert_idx = dest_tabs.GetPageCount() - - dest_tabs.InsertPage(page_info.window, page_info, insert_idx) - - if src_tabs.GetPageCount() == 0: - self.RemoveEmptyTabFrames() - - self.DoSizing() - dest_tabs.DoShowHide() - dest_tabs.Refresh() - - # force the set selection function reset the selection - self._curpage = -1 - - # set the active page to the one we just split off - self.SetSelectionToPage(page_info) - - self.UpdateHintWindowSize() - - # notify owner that the tab has been dragged - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, self.GetId()) - e.SetSelection(event.GetSelection()) - e.SetOldSelection(event.GetSelection()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def OnTabCancelDrag(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_CANCEL_DRAG`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - tabs = event.GetEventObject() - if not tabs.GetEnabled(event.GetSelection()): - return - - self._mgr.HideHint() - - src_tabs = event.GetEventObject() - if not src_tabs: - raise Exception("no source object?") - - - def IsMouseWellOutsideWindow(self): - """ Returns whether the mouse is well outside the :class:`AuiNotebook` screen rectangle. """ - - screen_rect = self.GetScreenRect() - screen_rect.Inflate(50, 50) - - return not screen_rect.Contains(wx.GetMousePosition()) - - - def FloatPage(self, page_index): - """ - Float the page in `page_index` by reparenting it to a floating frame. - - :param integer `page_index`: the index of the page to be floated. - - .. warning:: - - When the notebook is more or less full screen, tabs cannot be dragged far - enough outside of the notebook to become floating pages. - - """ - - root_manager = framemanager.GetManager(self) - page_title = self.GetPageText(page_index) - page_contents = self.GetPage(page_index) - page_bitmap = self.GetPageBitmap(page_index) - text_colour = self.GetPageTextColour(page_index) - info = self.GetPageInfo(page_index) - - if root_manager and root_manager != self._mgr: - root_manager = framemanager.GetManager(self) - - if hasattr(page_contents, "__floating_size__"): - floating_size = wx.Size(*page_contents.__floating_size__) - else: - floating_size = page_contents.GetBestSize() - if floating_size == wx.DefaultSize: - floating_size = wx.Size(300, 200) - - page_contents.__page_index__ = page_index - page_contents.__aui_notebook__ = self - page_contents.__text_colour__ = text_colour - page_contents.__control__ = info.control - - if info.control: - info.control.Reparent(page_contents) - info.control.Hide() - info.control = None - - self.RemovePage(page_index) - self.RemoveEmptyTabFrames() - - pane_info = framemanager.AuiPaneInfo().Float().FloatingPosition(wx.GetMousePosition()). \ - FloatingSize(floating_size).BestSize(floating_size).Name("__floating__%s"%page_title). \ - Caption(page_title).Icon(page_bitmap) - root_manager.AddPane(page_contents, pane_info) - root_manager.Bind(framemanager.EVT_AUI_PANE_CLOSE, self.OnCloseFloatingPage) - self.GetActiveTabCtrl().DoShowHide() - self.DoSizing() - root_manager.Update() - - else: - frame = wx.Frame(self, title=page_title, - style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_TOOL_WINDOW| - wx.FRAME_FLOAT_ON_PARENT | wx.FRAME_NO_TASKBAR) - - if info.control: - info.control.Reparent(frame) - info.control.Hide() - - frame.bitmap = page_bitmap - frame.page_index = page_index - frame.text_colour = text_colour - frame.control = info.control - page_contents.Reparent(frame) - frame.Bind(wx.EVT_CLOSE, self.OnCloseFloatingPage) - frame.Move(wx.GetMousePosition()) - frame.Show() - self.RemovePage(page_index) - - self.RemoveEmptyTabFrames() - - wx.CallAfter(self.RemoveEmptyTabFrames) - - - def OnCloseFloatingPage(self, event): - """ - Handles the ``wx.EVT_CLOSE`` event for a floating page in :class:`AuiNotebook`. - - :param `event`: a :class:`CloseEvent` event to be processed. - """ - - root_manager = framemanager.GetManager(self) - if root_manager and root_manager != self._mgr: - pane = event.pane - if pane.name.startswith("__floating__"): - self.ReDockPage(pane) - return - - event.Skip() - else: - event.Skip() - frame = event.GetEventObject() - page_title = frame.GetTitle() - page_contents = list(frame.GetChildren())[-1] - page_contents.Reparent(self) - self.InsertPage(frame.page_index, page_contents, page_title, select=True, bitmap=frame.bitmap, control=frame.control) - - if frame.control: - src_tabs, idx = self.FindTab(page_contents) - frame.control.Reparent(src_tabs) - frame.control.Hide() - frame.control = None - - self.SetPageTextColour(frame.page_index, frame.text_colour) - - - def ReDockPage(self, pane): - """ - Re-docks a floating :class:`AuiNotebook` tab in the original position, when possible. - - :param `pane`: an instance of :class:`~lib.agw.aui.framemanager.AuiPaneInfo`. - """ - - root_manager = framemanager.GetManager(self) - - pane.window.__floating_size__ = wx.Size(*pane.floating_size) - page_index = pane.window.__page_index__ - text_colour = pane.window.__text_colour__ - control = pane.window.__control__ - - root_manager.DetachPane(pane.window) - self.InsertPage(page_index, pane.window, pane.caption, True, pane.icon, control=control) - - self.SetPageTextColour(page_index, text_colour) - self.GetActiveTabCtrl().DoShowHide() - self.DoSizing() - if control: - self.UpdateTabCtrlHeight(force=True) - - self._mgr.Update() - root_manager.Update() - - - def GetTabCtrlFromPoint(self, pt): - """ - Returns the tab control at the specified point. - - :param Point `pt`: the mouse location. - """ - - # if we've just removed the last tab from the source - # tab set, the remove the tab control completely - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - - tabframe = pane.window - if tabframe._tab_rect.Contains(pt): - return tabframe._tabs - - return None - - - def GetTabFrameFromTabCtrl(self, tab_ctrl): - """ - Returns the tab frame associated with a tab control. - - :param `tab_ctrl`: an instance of :class:`AuiTabCtrl`. - """ - - # if we've just removed the last tab from the source - # tab set, the remove the tab control completely - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - - tabframe = pane.window - if tabframe._tabs == tab_ctrl: - return tabframe - - return None - - - def GetTabFrameFromWindow(self, wnd): - """ - Returns the tab frame associated with a window. - - :param Window `wnd`: the window for which we want to locate the :class:`TabFrame`. - """ - - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - - tabframe = pane.window - for page in tabframe._tabs.GetPages(): - if wnd == page.window: - return tabframe - - return None - - - def RemoveEmptyTabFrames(self): - """ Removes all the empty tab frames. """ - - # if we've just removed the last tab from the source - # tab set, the remove the tab control completely - all_panes = self._mgr.GetAllPanes() - - for indx in xrange(len(all_panes)-1, -1, -1): - pane = all_panes[indx] - if pane.name == "dummy": - continue - - tab_frame = pane.window - if tab_frame._tabs.GetPageCount() == 0: - self._mgr.DetachPane(tab_frame) - tab_frame._tabs.Destroy() - tab_frame._tabs = None - del tab_frame - - # check to see if there is still a center pane - # if there isn't, make a frame the center pane - first_good = None - center_found = False - - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - - if pane.dock_direction == AUI_DOCK_CENTRE: - center_found = True - if not first_good: - first_good = pane.window - - if not center_found and first_good: - self._mgr.GetPane(first_good).Centre() - - if not self.IsBeingDeleted(): - self._mgr.Update() - - - def OnChildFocusNotebook(self, event): - """ - Handles the ``wx.EVT_CHILD_FOCUS`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`ChildFocusEvent` event to be processed. - """ - - # if we're dragging a tab, don't change the current selection. - # This code prevents a bug that used to happen when the hint window - # was hidden. In the bug, the focus would return to the notebook - # child, which would then enter this handler and call - # SetSelection, which is not desired turn tab dragging. - - event.Skip() - - all_panes = self._mgr.GetAllPanes() - for pane in all_panes: - if pane.name == "dummy": - continue - tabframe = pane.window - if tabframe._tabs.IsDragging(): - return - -## # change the tab selection to the child -## # which was focused -## idx = self._tabs.GetIdxFromWindow(event.GetWindow()) -## if idx != -1 and idx != self._curpage: -## self.SetSelection(idx) - - - def SetNavigatorIcon(self, bmp): - """ - Sets the icon used by the :class:`TabNavigatorWindow`. - - :param Bitmap `bmp`: the new bitmap for the :class:`TabNavigatorWindow`. - """ - - if isinstance(bmp, wx.Bitmap) and bmp.IsOk(): - self.NavigatorProps.Icon = bmp - else: - raise TypeError("SetNavigatorIcon requires a valid bitmap") - - - def OnNavigationKeyNotebook(self, event): - """ - Handles the ``wx.EVT_NAVIGATION_KEY`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`NavigationKeyEvent` event to be processed. - """ - - if event.IsWindowChange(): - if self._agwFlags & AUI_NB_SMART_TABS: - if not self._popupWin: - self._popupWin = TabNavigatorWindow(self, self.NavigatorProps) - self._popupWin.SetReturnCode(wx.ID_OK) - self._popupWin.ShowModal() - idx = self._popupWin.GetSelectedPage() - self._popupWin.Destroy() - self._popupWin = None - # Need to do CallAfter so that the selection and its - # associated events get processed outside the context of - # this key event. Not doing so causes odd issues with the - # window focus under certain use cases on Windows. - wx.CallAfter(self.SetSelection, idx, True) - else: - # a dialog is already opened - self._popupWin.OnNavigationKey(event) - return - else: - # change pages - # FIXME: the problem with this is that if we have a split notebook, - # we selection may go all over the place. - self.AdvanceSelection(event.GetDirection()) - - else: - # we get this event in 3 cases - # - # a) one of our pages might have generated it because the user TABbed - # out from it in which case we should propagate the event upwards and - # our parent will take care of setting the focus to prev/next sibling - # - # or - # - # b) the parent panel wants to give the focus to us so that we - # forward it to our selected page. We can't deal with this in - # OnSetFocus() because we don't know which direction the focus came - # from in this case and so can't choose between setting the focus to - # first or last panel child - # - # or - # - # c) we ourselves (see MSWTranslateMessage) generated the event - # - parent = self.GetParent() - - # the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE - isFromParent = event.GetEventObject() == parent - isFromSelf = event.GetEventObject() == self - - if isFromParent or isFromSelf: - - # no, it doesn't come from child, case (b) or (c): forward to a - # page but only if direction is backwards (TAB) or from ourselves, - if self.GetSelection() != wx.NOT_FOUND and (not event.GetDirection() or isFromSelf): - - # so that the page knows that the event comes from it's parent - # and is being propagated downwards - event.SetEventObject(self) - - page = self.GetPage(self.GetSelection()) - if not page.GetEventHandler().ProcessEvent(event): - page.SetFocus() - - #else: page manages focus inside it itself - - else: # otherwise set the focus to the notebook itself - - self.SetFocus() - - else: - - # send this event back for the 'wraparound' focus. - winFocus = event.GetCurrentFocus() - - if winFocus: - event.SetEventObject(self) - winFocus.GetEventHandler().ProcessEvent(event) - - - def OnTabButton(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_BUTTON`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - tabs = event.GetEventObject() - button_id = event.GetInt() - - if button_id == AUI_BUTTON_CLOSE: - - selection = event.GetSelection() - - if selection == -1: - - # if the close button is to the right, use the active - # page selection to determine which page to close - selection = tabs.GetActivePage() - - if selection == -1 or not tabs.GetEnabled(selection): - return - - if selection != -1: - - close_wnd = tabs.GetWindowFromIdx(selection) - - if close_wnd.GetName() == "__fake__page__": - # This is a notebook preview - previous_active, page_status = close_wnd.__previousStatus - for page, status in zip(tabs.GetPages(), page_status): - page.enabled = status - - main_idx = self._tabs.GetIdxFromWindow(close_wnd) - self.DeletePage(main_idx) - - if previous_active >= 0: - tabs.SetActivePage(previous_active) - page_count = tabs.GetPageCount() - selection = -1 - - for page in xrange(page_count): - # remove the page from the source tabs - page_info = tabs.GetPage(page) - if page_info.active: - selection = page - break - - tabs.DoShowHide() - self.DoSizing() - tabs.Refresh() - - if selection >= 0: - wx.CallAfter(tabs.MakeTabVisible, selection, self) - - # Don't fire the event - return - - # ask owner if it's ok to close the tab - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, self.GetId()) - idx = self._tabs.GetIdxFromWindow(close_wnd) - e.SetSelection(idx) - e.SetOldSelection(event.GetSelection()) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - if not e.IsAllowed(): - return - - if repr(close_wnd.__class__).find("AuiMDIChildFrame") >= 0: - close_wnd.Close() - - else: - main_idx = self._tabs.GetIdxFromWindow(close_wnd) - self.DeletePage(main_idx) - - # notify owner that the tab has been closed - e2 = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, self.GetId()) - e2.SetSelection(idx) - e2.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e2) - - if self.GetPageCount() == 0: - mgr = self.GetAuiManager() - win = mgr.GetManagedWindow() - win.SendSizeEvent() - - - def OnTabMiddleDown(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_TAB_MIDDLE_DOWN`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - tabs = event.GetEventObject() - if not tabs.GetEnabled(event.GetSelection()): - return - - # patch event through to owner - wnd = tabs.GetWindowFromIdx(event.GetSelection()) - - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, self.GetId()) - e.SetSelection(self._tabs.GetIdxFromWindow(wnd)) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def OnTabMiddleUp(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_TAB_MIDDLE_UP`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - tabs = event.GetEventObject() - if not tabs.GetEnabled(event.GetSelection()): - return - - # if the AUI_NB_MIDDLE_CLICK_CLOSE is specified, middle - # click should act like a tab close action. However, first - # give the owner an opportunity to handle the middle up event - # for custom action - - wnd = tabs.GetWindowFromIdx(event.GetSelection()) - - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, self.GetId()) - e.SetSelection(self._tabs.GetIdxFromWindow(wnd)) - e.SetEventObject(self) - if self.GetEventHandler().ProcessEvent(e): - return - if not e.IsAllowed(): - return - - # check if we are supposed to close on middle-up - if self._agwFlags & AUI_NB_MIDDLE_CLICK_CLOSE == 0: - return - - # simulate the user pressing the close button on the tab - event.SetInt(AUI_BUTTON_CLOSE) - self.OnTabButton(event) - - - def OnTabRightDown(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_TAB_RIGHT_DOWN`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - tabs = event.GetEventObject() - if not tabs.GetEnabled(event.GetSelection()): - return - - # patch event through to owner - wnd = tabs.GetWindowFromIdx(event.GetSelection()) - - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, self.GetId()) - e.SetSelection(self._tabs.GetIdxFromWindow(wnd)) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def OnTabRightUp(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_TAB_RIGHT_UP`` event for :class:`AuiNotebook`. - - :param `event`: a :class:`AuiNotebookEvent` event to be processed. - """ - - tabs = event.GetEventObject() - if not tabs.GetEnabled(event.GetSelection()): - return - - # patch event through to owner - wnd = tabs.GetWindowFromIdx(event.GetSelection()) - - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, self.GetId()) - e.SetSelection(self._tabs.GetIdxFromWindow(wnd)) - e.SetEventObject(self) - self.GetEventHandler().ProcessEvent(e) - - - def SetNormalFont(self, font): - """ - Sets the normal font for drawing tab labels. - - :param Font `font`: the new font to use to draw tab labels in their normal, un-selected state. - """ - - self._normal_font = font - self.GetArtProvider().SetNormalFont(font) - - - def SetSelectedFont(self, font): - """ - Sets the selected tab font for drawing tab labels. - - :param Font `font`: the new font to use to draw tab labels in their selected state. - """ - - self._selected_font = font - self.GetArtProvider().SetSelectedFont(font) - - - def SetMeasuringFont(self, font): - """ - Sets the font for calculating text measurements. - - :param Font `font`: the new font to use to measure tab label text extents. - """ - - self.GetArtProvider().SetMeasuringFont(font) - - - def SetFont(self, font): - """ - Sets the tab font. - - :param Font `font`: the new font to use to draw tab labels in their normal, un-selected state. - - :note: Overridden from :class:`PyPanel`. - """ - - wx.PyPanel.SetFont(self, font) - - selectedFont = wx.Font(font.GetPointSize(), font.GetFamily(), - font.GetStyle(), wx.BOLD, font.GetUnderlined(), - font.GetFaceName(), font.GetEncoding()) - - self.SetNormalFont(font) - self.SetSelectedFont(selectedFont) - self.SetMeasuringFont(selectedFont) - - # Recalculate tab container size based on new font - self.UpdateTabCtrlHeight(force=False) - self.DoSizing() - - return True - - - def GetTabCtrlHeight(self): - """ Returns the tab control height. """ - - return self._tab_ctrl_height - - - def GetHeightForPageHeight(self, pageHeight): - """ - Gets the height of the notebook for a given page height. - - :param integer `pageHeight`: the given page height. - """ - - self.UpdateTabCtrlHeight() - - tabCtrlHeight = self.GetTabCtrlHeight() - decorHeight = 2 - return tabCtrlHeight + pageHeight + decorHeight - - - def AdvanceSelection(self, forward=True, wrap=True): - """ - Cycles through the tabs. - - :param bool `forward`: whether to advance forward or backward; - :param bool `wrap`: ``True`` to return to the first tab if we reach the last tab. - - :note: The call to this function generates the page changing events. - """ - - tabCtrl = self.GetActiveTabCtrl() - newPage = -1 - - focusWin = tabCtrl.FindFocus() - activePage = tabCtrl.GetActivePage() - lenPages = len(tabCtrl.GetPages()) - - if lenPages == 1: - return False - - if forward: - if lenPages > 1: - - if activePage == -1 or activePage == lenPages - 1: - if not wrap: - return False - - newPage = 0 - - elif activePage < lenPages - 1: - newPage = activePage + 1 - - else: - - if lenPages > 1: - if activePage == -1 or activePage == 0: - if not wrap: - return False - - newPage = lenPages - 1 - - elif activePage > 0: - newPage = activePage - 1 - - - if newPage != -1: - if not self.GetEnabled(newPage): - return False - - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, tabCtrl.GetId()) - e.SetSelection(newPage) - e.SetOldSelection(activePage) - e.SetEventObject(tabCtrl) - self.GetEventHandler().ProcessEvent(e) - -## if focusWin: -## focusWin.SetFocus() - - return True - - - def ShowWindowMenu(self): - """ - Shows the window menu for the active tab control associated with this - notebook, and returns ``True`` if a selection was made. - """ - - tabCtrl = self.GetActiveTabCtrl() - idx = tabCtrl.GetArtProvider().ShowDropDown(tabCtrl, tabCtrl.GetPages(), tabCtrl.GetActivePage()) - - if not self.GetEnabled(idx): - return False - - if idx != -1: - e = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, tabCtrl.GetId()) - e.SetSelection(idx) - e.SetOldSelection(tabCtrl.GetActivePage()) - e.SetEventObject(tabCtrl) - self.GetEventHandler().ProcessEvent(e) - - return True - - else: - - return False - - - def AddTabAreaButton(self, id, location, normal_bitmap=wx.NullBitmap, disabled_bitmap=wx.NullBitmap): - """ - Adds a button in the tab area. - - :param integer `id`: the button identifier. This can be one of the following: - - ============================== ================================= - Button Identifier Description - ============================== ================================= - ``AUI_BUTTON_CLOSE`` Shows a close button on the tab area - ``AUI_BUTTON_WINDOWLIST`` Shows a window list button on the tab area - ``AUI_BUTTON_LEFT`` Shows a left button on the tab area - ``AUI_BUTTON_RIGHT`` Shows a right button on the tab area - ============================== ================================= - - :param integer `location`: the button location. Can be ``wx.LEFT`` or ``wx.RIGHT``; - :param Bitmap `normal_bitmap`: the bitmap for an enabled tab; - :param Bitmap `disabled_bitmap`: the bitmap for a disabled tab. - """ - - active_tabctrl = self.GetActiveTabCtrl() - active_tabctrl.AddButton(id, location, normal_bitmap, disabled_bitmap) - - - def RemoveTabAreaButton(self, id): - """ - Removes a button from the tab area. - - :param integer `id`: the button identifier. - - :see: :meth:`AddTabAreaButton` for a list of button identifiers. - """ - - active_tabctrl = self.GetActiveTabCtrl() - active_tabctrl.RemoveButton(id) - - - def CloneTabAreaButtons(self): - """ - Clones the tab area buttons when the :class:`AuiNotebook` is being split. - - :see: :meth:`AddTabAreaButton` - - :note: Standard buttons for :class:`AuiNotebook` are not cloned, only custom ones. - """ - - active_tabctrl = self.GetActiveTabCtrl() - clones = active_tabctrl.CloneButtons() - - return clones - - - def HasMultiplePages(self): - """ - This method should be overridden to return ``True`` if this window has multiple pages. All - standard class with multiple pages such as :class:`Notebook`, :class:`Listbook` and :class:`Treebook` - already override it to return ``True`` and user-defined classes with similar behaviour - should do it as well to allow the library to handle such windows appropriately. - - :note: Overridden from :class:`PyPanel`. - """ - - return True - - - def GetDefaultBorder(self): - """ Returns the default border style for :class:`AuiNotebook`. """ - - return wx.BORDER_NONE - - - def NotebookPreview(self, thumbnail_size=200): - """ - Generates a preview of all the pages in the notebook (MSW and GTK only). - - :param integer `thumbnail_size`: the maximum size of every page thumbnail - (default=200 pixels). - - :note: this functionality is currently unavailable on wxMAC. - """ - - if wx.Platform == "__WXMAC__": - return False - - tabCtrl = self.GetActiveTabCtrl() - activePage = tabCtrl.GetActivePage() - pages = tabCtrl.GetPages() - - pageStatus, pageText = [], [] - - for indx, page in enumerate(pages): - - pageStatus.append(page.enabled) - - if not page.enabled: - continue - - self.SetSelectionToPage(page) - pageText.append(page.caption) - - rect = page.window.GetScreenRect() - bmp = RescaleScreenShot(TakeScreenShot(rect), thumbnail_size) - - page.enabled = False - if indx == 0: - il = wx.ImageList(bmp.GetWidth(), bmp.GetHeight(), True) - - il.Add(bmp) - - # create the list control - listCtrl = wx.ListCtrl(self, style=wx.LC_ICON|wx.LC_AUTOARRANGE|wx.LC_HRULES|wx.LC_VRULES, - name="__fake__page__") - - # assign the image list to it - listCtrl.AssignImageList(il, wx.IMAGE_LIST_NORMAL) - listCtrl.__previousStatus = [activePage, pageStatus] - - # create some items for the list - for indx, text in enumerate(pageText): - listCtrl.InsertImageStringItem(10000, text, indx) - - self.AddPage(listCtrl, "AuiNotebook Preview", True, bitmap=auinotebook_preview.GetBitmap(), disabled_bitmap=wx.NullBitmap) - return True - - - def SetRenamable(self, page_idx, renamable): - """ - Sets whether a tab can be renamed via a left double-click or not. - - :param integer `page_idx`: the page index; - :param bool `renamable`: ``True`` if the page can be renamed. - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - # update our own tab catalog - page_info = self._tabs.GetPage(page_idx) - page_info.renamable = renamable - - # update what's on screen - ctrl, ctrl_idx = self.FindTab(page_info.window) - if not ctrl: - return False - - info = ctrl.GetPage(ctrl_idx) - info.renamable = page_info.renamable - - return True - - - def IsRenamable(self, page_idx): - """ - Returns whether a tab can be renamed or not. - - :param integer `page_idx`: the page index. - - :returns: ``True`` is a page can be renamed, ``False`` otherwise. - """ - - if page_idx >= self._tabs.GetPageCount(): - return False - - page_info = self._tabs.GetPage(page_idx) - return page_info.renamable - - - def OnRenameCancelled(self, page_index): - """ - Called by :class:`TabTextCtrl`, to cancel the changes and to send the - ``EVT_AUINOTEBOOK_END_LABEL_EDIT`` event. - - :param integer `page_index`: the page index in the notebook. - """ - - # let owner know that the edit was cancelled - evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_END_LABEL_EDIT, self.GetId()) - - evt.SetSelection(page_index) - evt.SetEventObject(self) - evt.SetLabel("") - evt.SetEditCanceled(True) - self.GetEventHandler().ProcessEvent(evt) - - - def OnRenameAccept(self, page_index, value): - """ - Called by :class:`TabTextCtrl`, to accept the changes and to send the - ``EVT_AUINOTEBOOK_END_LABEL_EDIT`` event. - - :param integer `page_index`: the page index in the notebook; - :param string `value`: the new label for the tab. - """ - - evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_END_LABEL_EDIT, self.GetId()) - evt.SetSelection(page_index) - evt.SetEventObject(self) - evt.SetLabel(value) - evt.SetEditCanceled(False) - - return not self.GetEventHandler().ProcessEvent(evt) or evt.IsAllowed() - - - def ResetTextControl(self): - """ Called by :class:`TabTextCtrl` when it marks itself for deletion. """ - - if not self._textCtrl: - return - - self._textCtrl.Destroy() - self._textCtrl = None - - # tab height might have changed - self.UpdateTabCtrlHeight(force=True) - - - def EditTab(self, page_index): - """ - Starts the editing of an item label, sending a ``EVT_AUINOTEBOOK_BEGIN_LABEL_EDIT`` event. - - :param integer `page_index`: the page index we want to edit. - """ - - if page_index >= self._tabs.GetPageCount(): - return False - - if not self.IsRenamable(page_index): - return False - - page_info = self._tabs.GetPage(page_index) - ctrl, ctrl_idx = self.FindTab(page_info.window) - if not ctrl: - return False - - evt = AuiNotebookEvent(wxEVT_COMMAND_AUINOTEBOOK_BEGIN_LABEL_EDIT, self.GetId()) - evt.SetSelection(page_index) - evt.SetEventObject(self) - if self.GetEventHandler().ProcessEvent(evt) and not evt.IsAllowed(): - # vetoed by user - return False - - if self._textCtrl is not None and page_info != self._textCtrl.item(): - self._textCtrl.StopEditing() - - self._textCtrl = TabTextCtrl(ctrl, page_info, page_index) - self._textCtrl.SetFocus() - - return True diff --git a/enaml/wx/wx_upstream/aui/dockart.py b/enaml/wx/wx_upstream/aui/dockart.py deleted file mode 100644 index 405d8f05f..000000000 --- a/enaml/wx/wx_upstream/aui/dockart.py +++ /dev/null @@ -1,1187 +0,0 @@ -""" -Dock art provider code - a dock provider provides all drawing functionality to -the AUI dock manager. This allows the dock manager to have a plugable look-and-feel. - -By default, a :class:`~lib.agw.aui.framemanager` uses an instance of this class called :mod:`~lib.agw.aui.dockart` -which provides bitmap art and a colour scheme that is adapted to the major platforms' -look. You can either derive from that class to alter its behaviour or write a -completely new dock art class. Call :meth:`AuiManager.SetArtProvider() ` -to make use this new dock art. -""" - -__author__ = "Andrea Gavana " -__date__ = "31 March 2009" - - -import wx -import types - -from aui_utilities import BitmapFromBits, StepColour, ChopText, GetBaseColour -from aui_utilities import DrawGradientRectangle, DrawMACCloseButton -from aui_utilities import DarkenBitmap, LightContrastColour -from aui_constants import * - -optionActive = 2**14 -""" Indicates that a pane is active and should display an active caption (if present). """ - -_ctypes = False - -# Try to import winxptheme for ModernDockArt -if wx.Platform == "__WXMSW__": - try: - import ctypes - import winxptheme - _ctypes = True - except ImportError: - pass - -# -- AuiDefaultDockArt class implementation -- - -class AuiDefaultDockArt(object): - """ - Dock art provider code - a dock provider provides all drawing functionality to the AUI dock manager. - This allows the dock manager to have a plugable look-and-feel. - - By default, a :class:`~lib.agw.aui.framemanager.AuiManager` uses an instance of this class called - :class:`AuiDefaultDockArt` which provides bitmap art and a colour scheme that is adapted to the major - platforms' look. You can either derive from that class to alter its behaviour or - write a completely new dock art class. - - Call :meth:`AuiManager.SetArtProvider() ` - to make use this new dock art. - - - **Metric Ordinals** - - These are the possible pane dock art settings for :class:`AuiDefaultDockArt`: - - ================================================ ====================================== - Metric Ordinal Constant Description - ================================================ ====================================== - ``AUI_DOCKART_SASH_SIZE`` Customizes the sash size - ``AUI_DOCKART_CAPTION_SIZE`` Customizes the caption size - ``AUI_DOCKART_GRIPPER_SIZE`` Customizes the gripper size - ``AUI_DOCKART_PANE_BORDER_SIZE`` Customizes the pane border size - ``AUI_DOCKART_PANE_BUTTON_SIZE`` Customizes the pane button size - ``AUI_DOCKART_BACKGROUND_COLOUR`` Customizes the background colour - ``AUI_DOCKART_BACKGROUND_GRADIENT_COLOUR`` Customizes the background gradient colour - ``AUI_DOCKART_SASH_COLOUR`` Customizes the sash colour - ``AUI_DOCKART_ACTIVE_CAPTION_COLOUR`` Customizes the active caption colour - ``AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR`` Customizes the active caption gradient colour - ``AUI_DOCKART_INACTIVE_CAPTION_COLOUR`` Customizes the inactive caption colour - ``AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR`` Customizes the inactive gradient caption colour - ``AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR`` Customizes the active caption text colour - ``AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR`` Customizes the inactive caption text colour - ``AUI_DOCKART_BORDER_COLOUR`` Customizes the border colour - ``AUI_DOCKART_GRIPPER_COLOUR`` Customizes the gripper colour - ``AUI_DOCKART_CAPTION_FONT`` Customizes the caption font - ``AUI_DOCKART_GRADIENT_TYPE`` Customizes the gradient type (no gradient, vertical or horizontal) - ``AUI_DOCKART_DRAW_SASH_GRIP`` Draw a sash grip on the sash - ``AUI_DOCKART_HINT_WINDOW_COLOUR`` Customizes the hint window background colour (currently light blue) - ================================================ ====================================== - - - **Gradient Types** - - These are the possible gradient dock art settings for :class:`AuiDefaultDockArt`: - - ============================================ ====================================== - Gradient Constant Description - ============================================ ====================================== - ``AUI_GRADIENT_NONE`` No gradient on the captions - ``AUI_GRADIENT_VERTICAL`` Vertical gradient on the captions - ``AUI_GRADIENT_HORIZONTAL`` Horizontal gradient on the captions - ============================================ ====================================== - - - **Button States** - - These are the possible pane button / :class:`~lib.agw.aui.auibook.AuiNotebook` button / - :class:`~lib.agw.aui.auibar.AuiToolBar` button states: - - ============================================ ====================================== - Button State Constant Description - ============================================ ====================================== - ``AUI_BUTTON_STATE_NORMAL`` Normal button state - ``AUI_BUTTON_STATE_HOVER`` Hovered button state - ``AUI_BUTTON_STATE_PRESSED`` Pressed button state - ``AUI_BUTTON_STATE_DISABLED`` Disabled button state - ``AUI_BUTTON_STATE_HIDDEN`` Hidden button state - ``AUI_BUTTON_STATE_CHECKED`` Checked button state - ============================================ ====================================== - - - **Button Identifiers** - - These are the possible pane button / :class:`~lib.agw.aui.auibook.AuiNotebook` button / - :class:`~lib.agw.aui.auibar.AuiToolBar` button identifiers: - - ============================================ ====================================== - Button Identifier Description - ============================================ ====================================== - ``AUI_BUTTON_CLOSE`` Shows a close button on the pane - ``AUI_BUTTON_MAXIMIZE_RESTORE`` Shows a maximize/restore button on the pane - ``AUI_BUTTON_MINIMIZE`` Shows a minimize button on the pane - ``AUI_BUTTON_PIN`` Shows a pin button on the pane - ``AUI_BUTTON_OPTIONS`` Shows an option button on the pane (not implemented) - ``AUI_BUTTON_WINDOWLIST`` Shows a window list button on the pane (for :class:`~lib.agw.aui.auibook.AuiNotebook`) - ``AUI_BUTTON_LEFT`` Shows a left button on the pane (for :class:`~lib.agw.aui.auibook.AuiNotebook`) - ``AUI_BUTTON_RIGHT`` Shows a right button on the pane (for :class:`~lib.agw.aui.auibook.AuiNotebook`) - ``AUI_BUTTON_UP`` Shows an up button on the pane (not implemented) - ``AUI_BUTTON_DOWN`` Shows a down button on the pane (not implemented) - ``AUI_BUTTON_CUSTOM1`` Shows a custom button on the pane (not implemented) - ``AUI_BUTTON_CUSTOM2`` Shows a custom button on the pane (not implemented) - ``AUI_BUTTON_CUSTOM3`` Shows a custom button on the pane (not implemented) - ============================================ ====================================== - - """ - - def __init__(self): - """ Default class constructor. """ - - self.Init() - - isMac = wx.Platform == "__WXMAC__" - - if isMac: - self._caption_font = wx.SMALL_FONT - else: - self._caption_font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False) - - self.SetDefaultPaneBitmaps(isMac) - self._restore_bitmap = wx.BitmapFromXPMData(restore_xpm) - - # default metric values - self._sash_size = 4 - - if isMac: - # This really should be implemented in wx.SystemSettings - # There is no way to do this that I am aware outside of using - # the cocoa python bindings. 8 pixels looks correct on my system - # so hard coding it for now. - - # How do I translate this?!? Not sure of the below implementation... - # SInt32 height; - # GetThemeMetric( kThemeMetricSmallPaneSplitterHeight , &height ); - # self._sash_size = height; - - self._sash_size = 8 # Carbon.Appearance.kThemeMetricPaneSplitterHeight - - elif wx.Platform == "__WXGTK__": - self._sash_size = wx.RendererNative.Get().GetSplitterParams(wx.GetTopLevelWindows()[0]).widthSash - - else: - self._sash_size = 4 - - self._caption_size = 19 - self._border_size = 1 - self._button_size = 14 - self._gripper_size = 9 - self._gradient_type = AUI_GRADIENT_VERTICAL - self._draw_sash = False - - - def Init(self): - """ Initializes the dock art. """ - - self.SetDefaultColours() - - isMac = wx.Platform == "__WXMAC__" - - if isMac: - self._active_caption_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT) - else: - self._active_caption_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVECAPTION) - - self._active_caption_gradient_colour = LightContrastColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT)) - self._active_caption_text_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT) - self._inactive_caption_text_colour = wx.BLACK - - - def SetDefaultColours(self, base_colour=None): - """ - Sets the default colours, which are calculated from the given base colour. - - :param `base_colour`: an instance of :class:`Colour`. If defaulted to ``None``, a colour - is generated accordingly to the platform and theme. - """ - - if base_colour is None: - base_colour = GetBaseColour() - - darker1_colour = StepColour(base_colour, 85) - darker2_colour = StepColour(base_colour, 75) - darker3_colour = StepColour(base_colour, 60) - darker4_colour = StepColour(base_colour, 40) - - self._background_colour = base_colour - self._background_gradient_colour = StepColour(base_colour, 180) - - self._inactive_caption_colour = darker1_colour - self._inactive_caption_gradient_colour = StepColour(base_colour, 97) - - self._sash_brush = wx.Brush(base_colour) - self._background_brush = wx.Brush(base_colour) - self._border_pen = wx.Pen(darker2_colour) - self._gripper_brush = wx.Brush(base_colour) - self._gripper_pen1 = wx.Pen(darker4_colour) - self._gripper_pen2 = wx.Pen(darker3_colour) - self._gripper_pen3 = wx.WHITE_PEN - - self._hint_background_colour = colourHintBackground - - - def GetMetric(self, id): - """ - Gets the value of a certain setting. - - :param integer `id`: can be one of the size values in `Metric Ordinals`. - """ - - - if id == AUI_DOCKART_SASH_SIZE: - return self._sash_size - elif id == AUI_DOCKART_CAPTION_SIZE: - return self._caption_size - elif id == AUI_DOCKART_GRIPPER_SIZE: - return self._gripper_size - elif id == AUI_DOCKART_PANE_BORDER_SIZE: - return self._border_size - elif id == AUI_DOCKART_PANE_BUTTON_SIZE: - return self._button_size - elif id == AUI_DOCKART_GRADIENT_TYPE: - return self._gradient_type - elif id == AUI_DOCKART_DRAW_SASH_GRIP: - return self._draw_sash - else: - raise Exception("Invalid Metric Ordinal.") - - - def SetMetric(self, id, new_val): - """ - Sets the value of a certain setting using `new_val` - - :param integer `id`: can be one of the size values in `Metric Ordinals`; - :param `new_val`: the new value of the setting. - """ - - if id == AUI_DOCKART_SASH_SIZE: - self._sash_size = new_val - elif id == AUI_DOCKART_CAPTION_SIZE: - self._caption_size = new_val - elif id == AUI_DOCKART_GRIPPER_SIZE: - self._gripper_size = new_val - elif id == AUI_DOCKART_PANE_BORDER_SIZE: - self._border_size = new_val - elif id == AUI_DOCKART_PANE_BUTTON_SIZE: - self._button_size = new_val - elif id == AUI_DOCKART_GRADIENT_TYPE: - self._gradient_type = new_val - elif id == AUI_DOCKART_DRAW_SASH_GRIP: - self._draw_sash = new_val - else: - raise Exception("Invalid Metric Ordinal.") - - - def GetColor(self, id): - """ - Gets the colour of a certain setting. - - :param integer `id`: can be one of the colour values in `Metric Ordinals`. - """ - - if id == AUI_DOCKART_BACKGROUND_COLOUR: - return self._background_brush.GetColour() - elif id == AUI_DOCKART_BACKGROUND_GRADIENT_COLOUR: - return self._background_gradient_colour - elif id == AUI_DOCKART_SASH_COLOUR: - return self._sash_brush.GetColour() - elif id == AUI_DOCKART_INACTIVE_CAPTION_COLOUR: - return self._inactive_caption_colour - elif id == AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR: - return self._inactive_caption_gradient_colour - elif id == AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR: - return self._inactive_caption_text_colour - elif id == AUI_DOCKART_ACTIVE_CAPTION_COLOUR: - return self._active_caption_colour - elif id == AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR: - return self._active_caption_gradient_colour - elif id == AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR: - return self._active_caption_text_colour - elif id == AUI_DOCKART_BORDER_COLOUR: - return self._border_pen.GetColour() - elif id == AUI_DOCKART_GRIPPER_COLOUR: - return self._gripper_brush.GetColour() - elif id == AUI_DOCKART_HINT_WINDOW_COLOUR: - return self._hint_background_colour - else: - raise Exception("Invalid Colour Ordinal.") - - - def SetColor(self, id, colour): - """ - Sets the colour of a certain setting. - - :param integer `id`: can be one of the colour values in `Metric Ordinals`; - :param `colour`: the new value of the setting. - :type `colour`: :class:`Colour` or tuple or integer - """ - - if isinstance(colour, basestring): - colour = wx.NamedColour(colour) - elif isinstance(colour, types.TupleType): - colour = wx.Colour(*colour) - elif isinstance(colour, types.IntType): - colour = wx.ColourRGB(colour) - - if id == AUI_DOCKART_BACKGROUND_COLOUR: - self._background_brush.SetColour(colour) - elif id == AUI_DOCKART_BACKGROUND_GRADIENT_COLOUR: - self._background_gradient_colour = colour - elif id == AUI_DOCKART_SASH_COLOUR: - self._sash_brush.SetColour(colour) - elif id == AUI_DOCKART_INACTIVE_CAPTION_COLOUR: - self._inactive_caption_colour = colour - if not self._custom_pane_bitmaps and wx.Platform == "__WXMAC__": - # No custom bitmaps for the pane close button - # Change the MAC close bitmap colour - self._inactive_close_bitmap = DrawMACCloseButton(wx.WHITE, colour) - - elif id == AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR: - self._inactive_caption_gradient_colour = colour - elif id == AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR: - self._inactive_caption_text_colour = colour - elif id == AUI_DOCKART_ACTIVE_CAPTION_COLOUR: - self._active_caption_colour = colour - if not self._custom_pane_bitmaps and wx.Platform == "__WXMAC__": - # No custom bitmaps for the pane close button - # Change the MAC close bitmap colour - self._active_close_bitmap = DrawMACCloseButton(wx.WHITE, colour) - - elif id == AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR: - self._active_caption_gradient_colour = colour - elif id == AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR: - self._active_caption_text_colour = colour - elif id == AUI_DOCKART_BORDER_COLOUR: - self._border_pen.SetColour(colour) - elif id == AUI_DOCKART_GRIPPER_COLOUR: - self._gripper_brush.SetColour(colour) - self._gripper_pen1.SetColour(StepColour(colour, 40)) - self._gripper_pen2.SetColour(StepColour(colour, 60)) - elif id == AUI_DOCKART_HINT_WINDOW_COLOUR: - self._hint_background_colour = colour - else: - raise Exception("Invalid Colour Ordinal.") - - - GetColour = GetColor - SetColour = SetColor - - def SetFont(self, id, font): - """ - Sets a font setting. - - :param integer `id`: must be ``AUI_DOCKART_CAPTION_FONT``; - :param `font`: an instance of :class:`Font`. - """ - - if id == AUI_DOCKART_CAPTION_FONT: - self._caption_font = font - - - def GetFont(self, id): - """ - Gets a font setting. - - :param integer `id`: must be ``AUI_DOCKART_CAPTION_FONT``, otherwise :class:`NullFont` is returned. - """ - - if id == AUI_DOCKART_CAPTION_FONT: - return self._caption_font - - return wx.NullFont - - - def DrawSash(self, dc, window, orient, rect): - """ - Draws a sash between two windows. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param integer `orient`: the sash orientation; - :param Rect `rect`: the sash rectangle. - """ - - # AG: How do we make this work?!? - # RendererNative does not use the sash_brush chosen by the user - # and the rect.GetSize() is ignored as the sash is always drawn - # 3 pixel wide - # wx.RendererNative.Get().DrawSplitterSash(window, dc, rect.GetSize(), pos, orient) - - dc.SetPen(wx.TRANSPARENT_PEN) - dc.SetBrush(self._sash_brush) - dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) - - draw_sash = self.GetMetric(AUI_DOCKART_DRAW_SASH_GRIP) - if draw_sash: - self.DrawSashGripper(dc, orient, rect) - - - def DrawBackground(self, dc, window, orient, rect): - """ - Draws a background. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param integer `orient`: the gradient (if any) orientation; - :param Rect `rect`: the background rectangle. - """ - - dc.SetPen(wx.TRANSPARENT_PEN) - if wx.Platform == "__WXMAC__": - # we have to clear first, otherwise we are drawing a light striped pattern - # over an already darker striped background - dc.SetBrush(wx.WHITE_BRUSH) - dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) - - DrawGradientRectangle(dc, rect, self._background_brush.GetColour(), - self._background_gradient_colour, - AUI_GRADIENT_HORIZONTAL, rect.x, 700) - - - def DrawBorder(self, dc, window, rect, pane): - """ - Draws the pane border. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param Rect `rect`: the border rectangle; - :param `pane`: the pane for which the border is drawn. - """ - - drect = wx.Rect(*rect) - - dc.SetPen(self._border_pen) - dc.SetBrush(wx.TRANSPARENT_BRUSH) - - border_width = self.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE) - - if pane.IsToolbar(): - - for ii in xrange(0, border_width): - - dc.SetPen(wx.WHITE_PEN) - dc.DrawLine(drect.x, drect.y, drect.x+drect.width, drect.y) - dc.DrawLine(drect.x, drect.y, drect.x, drect.y+drect.height) - dc.SetPen(self._border_pen) - dc.DrawLine(drect.x, drect.y+drect.height-1, - drect.x+drect.width, drect.y+drect.height-1) - dc.DrawLine(drect.x+drect.width-1, drect.y, - drect.x+drect.width-1, drect.y+drect.height) - drect.Deflate(1, 1) - - else: - - for ii in xrange(0, border_width): - - dc.DrawRectangle(drect.x, drect.y, drect.width, drect.height) - drect.Deflate(1, 1) - - - def DrawCaptionBackground(self, dc, rect, pane): - """ - Draws the text caption background in the pane. - - :param `dc`: a :class:`DC` device context; - :param Rect `rect`: the text caption rectangle; - :param `pane`: the pane for which the text background is drawn. - """ - - active = pane.state & optionActive - - if self._gradient_type == AUI_GRADIENT_NONE: - if active: - dc.SetBrush(wx.Brush(self._active_caption_colour)) - else: - dc.SetBrush(wx.Brush(self._inactive_caption_colour)) - - dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) - - else: - - switch_gradient = pane.HasCaptionLeft() - gradient_type = self._gradient_type - if switch_gradient: - gradient_type = (self._gradient_type == AUI_GRADIENT_HORIZONTAL and [AUI_GRADIENT_VERTICAL] or \ - [AUI_GRADIENT_HORIZONTAL])[0] - - if active: - if wx.Platform == "__WXMAC__": - DrawGradientRectangle(dc, rect, self._active_caption_colour, - self._active_caption_gradient_colour, - gradient_type) - else: - DrawGradientRectangle(dc, rect, self._active_caption_gradient_colour, - self._active_caption_colour, - gradient_type) - else: - if wx.Platform == "__WXMAC__": - DrawGradientRectangle(dc, rect, self._inactive_caption_gradient_colour, - self._inactive_caption_colour, - gradient_type) - else: - DrawGradientRectangle(dc, rect, self._inactive_caption_colour, - self._inactive_caption_gradient_colour, - gradient_type) - - - def DrawIcon(self, dc, rect, pane): - """ - Draws the icon in the pane caption area. - - :param `dc`: a :class:`DC` device context; - :param Rect `rect`: the pane caption rectangle; - :param `pane`: the pane for which the icon is drawn. - """ - - # Draw the icon centered vertically - if pane.icon.Ok(): - if pane.HasCaptionLeft(): - bmp = wx.ImageFromBitmap(pane.icon).Rotate90(clockwise=False) - dc.DrawBitmap(bmp.ConvertToBitmap(), rect.x+(rect.width-pane.icon.GetWidth())/2, rect.y+rect.height-2-pane.icon.GetHeight(), True) - else: - dc.DrawBitmap(pane.icon, rect.x+2, rect.y+(rect.height-pane.icon.GetHeight())/2, True) - - - def DrawCaption(self, dc, window, text, rect, pane): - """ - Draws the text in the pane caption. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param string `text`: the text to be displayed; - :param Rect `rect`: the pane caption rectangle; - :param `pane`: the pane for which the text is drawn. - """ - - dc.SetPen(wx.TRANSPARENT_PEN) - dc.SetFont(self._caption_font) - - self.DrawCaptionBackground(dc, rect, pane) - - if pane.state & optionActive: - dc.SetTextForeground(self._active_caption_text_colour) - else: - dc.SetTextForeground(self._inactive_caption_text_colour) - - w, h = dc.GetTextExtent("ABCDEFHXfgkj") - - clip_rect = wx.Rect(*rect) - btns = pane.CountButtons() - - captionLeft = pane.HasCaptionLeft() - variable = (captionLeft and [rect.height] or [rect.width])[0] - - variable -= 3 # text offset - variable -= 2 # button padding - - caption_offset = 0 - if pane.icon: - if captionLeft: - caption_offset += pane.icon.GetHeight() + 3 - else: - caption_offset += pane.icon.GetWidth() + 3 - - self.DrawIcon(dc, rect, pane) - - variable -= caption_offset - variable -= btns*(self._button_size + self._border_size) - draw_text = ChopText(dc, text, variable) - - if captionLeft: - dc.DrawRotatedText(draw_text, rect.x+(rect.width/2)-(h/2)-1, rect.y+rect.height-3-caption_offset, 90) - else: - dc.DrawText(draw_text, rect.x+3+caption_offset, rect.y+(rect.height/2)-(h/2)-1) - - - def RequestUserAttention(self, dc, window, text, rect, pane): - """ - Requests the user attention by intermittently highlighting the pane caption. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param string `text`: the text to be displayed; - :param Rect `rect`: the pane caption rectangle; - :param `pane`: the pane for which we want to attract the user attention. - """ - - state = pane.state - pane.state &= ~optionActive - - for indx in xrange(6): - active = (indx%2 == 0 and [True] or [False])[0] - if active: - pane.state |= optionActive - else: - pane.state &= ~optionActive - - self.DrawCaptionBackground(dc, rect, pane) - self.DrawCaption(dc, window, text, rect, pane) - wx.SafeYield() - wx.MilliSleep(350) - - pane.state = state - - - def DrawGripper(self, dc, window, rect, pane): - """ - Draws a gripper on the pane. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param Rect `rect`: the pane caption rectangle; - :param `pane`: the pane for which the gripper is drawn. - """ - - dc.SetPen(wx.TRANSPARENT_PEN) - dc.SetBrush(self._gripper_brush) - - dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) - - if not pane.HasGripperTop(): - y = 4 - while 1: - dc.SetPen(self._gripper_pen1) - dc.DrawPoint(rect.x+3, rect.y+y) - dc.SetPen(self._gripper_pen2) - dc.DrawPoint(rect.x+3, rect.y+y+1) - dc.DrawPoint(rect.x+4, rect.y+y) - dc.SetPen(self._gripper_pen3) - dc.DrawPoint(rect.x+5, rect.y+y+1) - dc.DrawPoint(rect.x+5, rect.y+y+2) - dc.DrawPoint(rect.x+4, rect.y+y+2) - y = y + 4 - if y > rect.GetHeight() - 4: - break - else: - x = 4 - while 1: - dc.SetPen(self._gripper_pen1) - dc.DrawPoint(rect.x+x, rect.y+3) - dc.SetPen(self._gripper_pen2) - dc.DrawPoint(rect.x+x+1, rect.y+3) - dc.DrawPoint(rect.x+x, rect.y+4) - dc.SetPen(self._gripper_pen3) - dc.DrawPoint(rect.x+x+1, rect.y+5) - dc.DrawPoint(rect.x+x+2, rect.y+5) - dc.DrawPoint(rect.x+x+2, rect.y+4) - x = x + 4 - if x > rect.GetWidth() - 4: - break - - - def DrawPaneButton(self, dc, window, button, button_state, _rect, pane): - """ - Draws a pane button in the pane caption area. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param integer `button`: the button to be drawn; - :param integer `button_state`: the pane button state; - :param Rect `_rect`: the pane caption rectangle; - :param `pane`: the pane for which the button is drawn. - """ - - if not pane: - return - - if button == AUI_BUTTON_CLOSE: - if pane.state & optionActive: - bmp = self._active_close_bitmap - else: - bmp = self._inactive_close_bitmap - - elif button == AUI_BUTTON_PIN: - if pane.state & optionActive: - bmp = self._active_pin_bitmap - else: - bmp = self._inactive_pin_bitmap - - elif button == AUI_BUTTON_MAXIMIZE_RESTORE: - if pane.IsMaximized(): - if pane.state & optionActive: - bmp = self._active_restore_bitmap - else: - bmp = self._inactive_restore_bitmap - else: - if pane.state & optionActive: - bmp = self._active_maximize_bitmap - else: - bmp = self._inactive_maximize_bitmap - - elif button == AUI_BUTTON_MINIMIZE: - if pane.state & optionActive: - bmp = self._active_minimize_bitmap - else: - bmp = self._inactive_minimize_bitmap - - isVertical = pane.HasCaptionLeft() - - rect = wx.Rect(*_rect) - - if isVertical: - old_x = rect.x - rect.x = rect.x + (rect.width/2) - (bmp.GetWidth()/2) - rect.width = old_x + rect.width - rect.x - 1 - else: - old_y = rect.y - rect.y = rect.y + (rect.height/2) - (bmp.GetHeight()/2) - rect.height = old_y + rect.height - rect.y - 1 - - if button_state == AUI_BUTTON_STATE_PRESSED: - rect.x += 1 - rect.y += 1 - - if button_state in [AUI_BUTTON_STATE_HOVER, AUI_BUTTON_STATE_PRESSED]: - - if pane.state & optionActive: - - dc.SetBrush(wx.Brush(StepColour(self._active_caption_colour, 120))) - dc.SetPen(wx.Pen(StepColour(self._active_caption_colour, 70))) - - else: - - dc.SetBrush(wx.Brush(StepColour(self._inactive_caption_colour, 120))) - dc.SetPen(wx.Pen(StepColour(self._inactive_caption_colour, 70))) - - if wx.Platform != "__WXMAC__": - # draw the background behind the button - dc.DrawRectangle(rect.x, rect.y, 15, 15) - else: - # Darker the bitmap a bit - bmp = DarkenBitmap(bmp, self._active_caption_colour, StepColour(self._active_caption_colour, 110)) - - if isVertical: - bmp = wx.ImageFromBitmap(bmp).Rotate90(clockwise=False).ConvertToBitmap() - - # draw the button itself - dc.DrawBitmap(bmp, rect.x, rect.y, True) - - - def DrawSashGripper(self, dc, orient, rect): - """ - Draws a sash gripper on a sash between two windows. - - :param `dc`: a :class:`DC` device context; - :param integer `orient`: the sash orientation; - :param Rect `rect`: the sash rectangle. - """ - - dc.SetBrush(self._gripper_brush) - - if orient == wx.HORIZONTAL: # horizontal sash - - x = rect.x + int((1.0/4.0)*rect.width) - xend = rect.x + int((3.0/4.0)*rect.width) - y = rect.y + (rect.height/2) - 1 - - while 1: - dc.SetPen(self._gripper_pen3) - dc.DrawRectangle(x, y, 2, 2) - dc.SetPen(self._gripper_pen2) - dc.DrawPoint(x+1, y+1) - x = x + 5 - - if x >= xend: - break - - else: - - y = rect.y + int((1.0/4.0)*rect.height) - yend = rect.y + int((3.0/4.0)*rect.height) - x = rect.x + (rect.width/2) - 1 - - while 1: - dc.SetPen(self._gripper_pen3) - dc.DrawRectangle(x, y, 2, 2) - dc.SetPen(self._gripper_pen2) - dc.DrawPoint(x+1, y+1) - y = y + 5 - - if y >= yend: - break - - - def SetDefaultPaneBitmaps(self, isMac): - """ - Assigns the default pane bitmaps. - - :param bool `isMac`: whether we are on wxMAC or not. - """ - - if isMac: - self._inactive_close_bitmap = DrawMACCloseButton(wx.WHITE, self._inactive_caption_colour) - self._active_close_bitmap = DrawMACCloseButton(wx.WHITE, self._active_caption_colour) - else: - self._inactive_close_bitmap = BitmapFromBits(close_bits, 16, 16, self._inactive_caption_text_colour) - self._active_close_bitmap = BitmapFromBits(close_bits, 16, 16, self._active_caption_text_colour) - - if isMac: - self._inactive_maximize_bitmap = BitmapFromBits(max_bits, 16, 16, wx.WHITE) - self._active_maximize_bitmap = BitmapFromBits(max_bits, 16, 16, wx.WHITE) - else: - self._inactive_maximize_bitmap = BitmapFromBits(max_bits, 16, 16, self._inactive_caption_text_colour) - self._active_maximize_bitmap = BitmapFromBits(max_bits, 16, 16, self._active_caption_text_colour) - - if isMac: - self._inactive_restore_bitmap = BitmapFromBits(restore_bits, 16, 16, wx.WHITE) - self._active_restore_bitmap = BitmapFromBits(restore_bits, 16, 16, wx.WHITE) - else: - self._inactive_restore_bitmap = BitmapFromBits(restore_bits, 16, 16, self._inactive_caption_text_colour) - self._active_restore_bitmap = BitmapFromBits(restore_bits, 16, 16, self._active_caption_text_colour) - - if isMac: - self._inactive_minimize_bitmap = BitmapFromBits(minimize_bits, 16, 16, wx.WHITE) - self._active_minimize_bitmap = BitmapFromBits(minimize_bits, 16, 16, wx.WHITE) - else: - self._inactive_minimize_bitmap = BitmapFromBits(minimize_bits, 16, 16, self._inactive_caption_text_colour) - self._active_minimize_bitmap = BitmapFromBits(minimize_bits, 16, 16, self._active_caption_text_colour) - - self._inactive_pin_bitmap = BitmapFromBits(pin_bits, 16, 16, self._inactive_caption_text_colour) - self._active_pin_bitmap = BitmapFromBits(pin_bits, 16, 16, self._active_caption_text_colour) - - self._custom_pane_bitmaps = False - - - def SetCustomPaneBitmap(self, bmp, button, active, maximize=False): - """ - Sets a custom button bitmap for the pane button. - - :param Bitmap `bmp`: the actual bitmap to set; - :param integer `button`: the button identifier; - :param bool `active`: whether it is the bitmap for the active button or not; - :param bool `maximize`: used to distinguish between the maximize and restore bitmaps. - """ - - if bmp.GetWidth() > 16 or bmp.GetHeight() > 16: - raise Exception("The input bitmap is too big") - - if button == AUI_BUTTON_CLOSE: - if active: - self._active_close_bitmap = bmp - else: - self._inactive_close_bitmap = bmp - - if wx.Platform == "__WXMAC__": - self._custom_pane_bitmaps = True - - elif button == AUI_BUTTON_PIN: - if active: - self._active_pin_bitmap = bmp - else: - self._inactive_pin_bitmap = bmp - - elif button == AUI_BUTTON_MAXIMIZE_RESTORE: - if maximize: - if active: - self._active_maximize_bitmap = bmp - else: - self._inactive_maximize_bitmap = bmp - else: - if active: - self._active_restore_bitmap = bmp - else: - self._inactive_restore_bitmap = bmp - - elif button == AUI_BUTTON_MINIMIZE: - if active: - self._active_minimize_bitmap = bmp - else: - self._inactive_minimize_bitmap = bmp - - -if _ctypes: - class RECT(ctypes.Structure): - """ Used to handle :class:`ModernDockArt` on Windows XP/Vista/7. """ - _fields_ = [('left', ctypes.c_ulong),('top', ctypes.c_ulong),('right', ctypes.c_ulong),('bottom', ctypes.c_ulong)] - - def dump(self): - """ Dumps `self` as a :class:`Rect`. """ - return map(int, (self.left, self.top, self.right, self.bottom)) - - - class SIZE(ctypes.Structure): - """ Used to handle :class:`ModernDockArt` on Windows XP/Vista/7. """ - _fields_ = [('x', ctypes.c_long),('y', ctypes.c_long)] - - -class ModernDockArt(AuiDefaultDockArt): - """ - ModernDockArt is a custom `AuiDockArt` class, that implements a look similar to Firefox and other recents applications. - - Is uses the `winxptheme `_ module and - XP themes whenever possible, so it should look good even if the user has a custom theme. - - :note: This dock art is Windows only and will only work if you have installed - Mark Hammond's `pywin32` module (http://sourceforge.net/projects/pywin32/). - """ - - def __init__(self, win): - """ - Default class constructor. - - :param Window `win`: the window managed by :class:`~lib.agw.aui.framemanager.AuiManager`. - """ - - AuiDefaultDockArt.__init__(self) - - self.win = win - - # Get the size of a small close button (themed) - hwnd = self.win.GetHandle() - self.usingTheme = False - - if _ctypes: - self.hTheme1 = winxptheme.OpenThemeData(hwnd, "Window") - self.usingTheme = True - - if not self.hTheme1: - self.usingTheme = False - - self._button_size = 13 - - self._button_border_size = 3 - self._caption_text_indent = 6 - self._caption_size = 22 - - # We only highlight the active pane with the caption text being in bold. - # So we do not want a special colour for active elements. - self._active_close_bitmap = self._inactive_close_bitmap - - self.Init() - - - def Init(self): - """ Initializes the dock art. """ - - AuiDefaultDockArt.Init(self) - - self._active_caption_colour = self._inactive_caption_colour - self._active_caption_text_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_CAPTIONTEXT) - self._inactive_caption_text_colour = self._active_caption_text_colour - - - def DrawCaption(self, dc, window, text, rect, pane): - """ - Draws the text in the pane caption. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param string `text`: the text to be displayed; - :param Rect `rect`: the pane caption rectangle; - :param `pane`: the pane for which the text is drawn. - """ - - dc.SetPen(wx.TRANSPARENT_PEN) - self.DrawCaptionBackground(dc, rect, pane) - - active = ((pane.state & optionActive) and [True] or [False])[0] - - self._caption_font.SetWeight(wx.FONTWEIGHT_BOLD) - dc.SetFont(self._caption_font) - - if active: - dc.SetTextForeground(self._active_caption_text_colour) - else: - dc.SetTextForeground(self._inactive_caption_text_colour) - - w, h = dc.GetTextExtent("ABCDEFHXfgkj") - - clip_rect = wx.Rect(*rect) - btns = pane.CountButtons() - - captionLeft = pane.HasCaptionLeft() - variable = (captionLeft and [rect.height] or [rect.width])[0] - - variable -= 3 # text offset - variable -= 2 # button padding - - caption_offset = 0 - if pane.icon: - if captionLeft: - caption_offset += pane.icon.GetHeight() + 3 - else: - caption_offset += pane.icon.GetWidth() + 3 - - self.DrawIcon(dc, rect, pane) - - diff = -2 - if self.usingTheme: - diff = -1 - - variable -= caption_offset - variable -= btns*(self._button_size + self._button_border_size) - draw_text = ChopText(dc, text, variable) - - if captionLeft: - dc.DrawRotatedText(draw_text, rect.x+(rect.width/2)-(h/2)-diff, rect.y+rect.height-3-caption_offset, 90) - else: - dc.DrawText(draw_text, rect.x+3+caption_offset, rect.y+(rect.height/2)-(h/2)-diff) - - - def DrawCaptionBackground(self, dc, rect, pane): - """ - Draws the text caption background in the pane. - - :param `dc`: a :class:`DC` device context; - :param Rect `rect`: the text caption rectangle; - :param `pane`: the pane for which we are drawing the caption background. - """ - - dc.SetBrush(self._background_brush) - dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) - - active = ((pane.state & optionActive) and [True] or [False])[0] - - if self.usingTheme: - - rectangle = wx.Rect() - - rc = RECT(rectangle.x, rectangle.y, rectangle.width, rectangle.height) - - # If rect x/y values are negative rc.right/bottom values will overflow and winxptheme.DrawThemeBackground - # will raise a TypeError. Ensure they are never negative. - rect.x = max(0, rect.x) - rect.y = max(0, rect.y) - - rc.top = rect.x - rc.left = rect.y - rc.right = rect.x + rect.width - rc.bottom = rect.y + rect.height - - if active: - winxptheme.DrawThemeBackground(self.hTheme1, dc.GetHDC(), 5, 1, (rc.top, rc.left, rc.right, rc.bottom), None) - else: - winxptheme.DrawThemeBackground(self.hTheme1, dc.GetHDC(), 5, 2, (rc.top, rc.left, rc.right, rc.bottom), None) - - else: - - AuiDefaultDockArt.DrawCaptionBackground(self, dc, rect, pane) - - - def RequestUserAttention(self, dc, window, text, rect, pane): - """ - Requests the user attention by intermittently highlighting the pane caption. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param string `text`: the text to be displayed; - :param Rect `rect`: the pane caption rectangle; - :param `pane`: the pane for which the text is drawn. - """ - - state = pane.state - pane.state &= ~optionActive - - for indx in xrange(6): - active = (indx%2 == 0 and [True] or [False])[0] - if active: - pane.state |= optionActive - else: - pane.state &= ~optionActive - - self.DrawCaptionBackground(dc, rect, pane) - self.DrawCaption(dc, window, text, rect, pane) - wx.SafeYield() - wx.MilliSleep(350) - - pane.state = state - - - def DrawPaneButton(self, dc, window, button, button_state, rect, pane): - """ - Draws a pane button in the pane caption area. - - :param `dc`: a :class:`DC` device context; - :param `window`: an instance of :class:`Window`; - :param integer `button`: the button to be drawn; - :param integer `button_state`: the pane button state; - :param Rect `rect`: the pane caption rectangle; - :param `pane`: the pane for which the button is drawn. - """ - - if self.usingTheme: - - hTheme = self.hTheme1 - - # Get the real button position (compensating for borders) - drect = wx.Rect(rect.x, rect.y, self._button_size, self._button_size) - - # Draw the themed close button - rc = RECT(0, 0, 0, 0) - if pane.HasCaptionLeft(): - rc.top = rect.x + self._button_border_size - rc.left = int(rect.y + 1.5*self._button_border_size) - rc.right = rect.x + self._button_size + self._button_border_size - rc.bottom = int(rect.y + self._button_size + 1.5*self._button_border_size) - else: - rc.top = rect.x - self._button_border_size - rc.left = int(rect.y + 1.5*self._button_border_size) - rc.right = rect.x + self._button_size- self._button_border_size - rc.bottom = int(rect.y + self._button_size + 1.5*self._button_border_size) - - if button == AUI_BUTTON_CLOSE: - btntype = 19 - - elif button == AUI_BUTTON_PIN: - btntype = 23 - - elif button == AUI_BUTTON_MAXIMIZE_RESTORE: - if not pane.IsMaximized(): - btntype = 17 - else: - btntype = 21 - else: - btntype = 15 - - state = 4 # CBS_DISABLED - - if pane.state & optionActive: - - if button_state == AUI_BUTTON_STATE_NORMAL: - state = 1 # CBS_NORMAL - - elif button_state == AUI_BUTTON_STATE_HOVER: - state = 2 # CBS_HOT - - elif button_state == AUI_BUTTON_STATE_PRESSED: - state = 3 # CBS_PUSHED - - else: - raise Exception("ERROR: Unknown State.") - - else: # inactive pane - - if button_state == AUI_BUTTON_STATE_NORMAL: - state = 5 # CBS_NORMAL - - elif button_state == AUI_BUTTON_STATE_HOVER: - state = 6 # CBS_HOT - - elif button_state == AUI_BUTTON_STATE_PRESSED: - state = 7 # CBS_PUSHED - - else: - raise Exception("ERROR: Unknown State.") - - try: - winxptheme.DrawThemeBackground(hTheme, dc.GetHDC(), btntype, state, (rc.top, rc.left, rc.right, rc.bottom), None) - except TypeError: - return - - else: - - # Fallback to default closebutton if themes are not enabled - rect2 = wx.Rect(rect.x-4, rect.y+2, rect.width, rect.height) - AuiDefaultDockArt.DrawPaneButton(self, dc, window, button, button_state, rect2, pane) - diff --git a/enaml/wx/wx_upstream/aui/framemanager.py b/enaml/wx/wx_upstream/aui/framemanager.py deleted file mode 100644 index e71fdbf26..000000000 --- a/enaml/wx/wx_upstream/aui/framemanager.py +++ /dev/null @@ -1,10715 +0,0 @@ -# --------------------------------------------------------------------------- # -# AUI Library wxPython IMPLEMENTATION -# -# Original C++ Code From Kirix (wxAUI). You Can Find It At: -# -# License: wxWidgets license -# -# http:#www.kirix.com/en/community/opensource/wxaui/about_wxaui.html -# -# Current wxAUI Version Tracked: wxWidgets 2.9.4 SVN HEAD -# -# -# Python Code By: -# -# Andrea Gavana, @ 23 Dec 2005 -# Latest Revision: 25 Apr 2012, 21.00 GMT -# -# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please -# Write To Me At: -# -# andrea.gavana@gmail.com -# andrea.gavana@maerskoil.com -# -# Or, Obviously, To The wxPython Mailing List!!! -# -# End Of Comments -# --------------------------------------------------------------------------- # - -""" -Description -=========== - -`framemanager.py` is the central module of the AUI class framework. - -:class:`AuiManager` manages the panes associated with it for a particular :class:`Frame`, using -a pane's :class:`AuiPaneInfo` information to determine each pane's docking and floating -behavior. AuiManager uses wxPython' sizer mechanism to plan the layout of each frame. -It uses a replaceable dock art class to do all drawing, so all drawing is localized -in one area, and may be customized depending on an application's specific needs. - -AuiManager works as follows: the programmer adds panes to the class, or makes -changes to existing pane properties (dock position, floating state, show state, etc...). -To apply these changes, AuiManager's :meth:`AuiManager.Update() ` function is called. This batch -processing can be used to avoid flicker, by modifying more than one pane at a time, -and then "committing" all of the changes at once by calling `Update()`. - -Panes can be added quite easily:: - - text1 = wx.TextCtrl(self, -1) - text2 = wx.TextCtrl(self, -1) - self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One")) - self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two")) - - self._mgr.Update() - - -Later on, the positions can be modified easily. The following will float an -existing pane in a tool window:: - - self._mgr.GetPane(text1).Float() - - -Layers, Rows and Directions, Positions -====================================== - -Inside AUI, the docking layout is figured out by checking several pane parameters. -Four of these are important for determining where a pane will end up. - -**Direction** - Each docked pane has a direction, `Top`, `Bottom`, `Left`, `Right`, or `Center`. -This is fairly self-explanatory. The pane will be placed in the location specified -by this variable. - -**Position** - More than one pane can be placed inside of a "dock". Imagine two panes -being docked on the left side of a window. One pane can be placed over another. -In proportionally managed docks, the pane position indicates it's sequential position, -starting with zero. So, in our scenario with two panes docked on the left side, the -top pane in the dock would have position 0, and the second one would occupy position 1. - -**Row** - A row can allow for two docks to be placed next to each other. One of the most -common places for this to happen is in the toolbar. Multiple toolbar rows are allowed, -the first row being in row 0, and the second in row 1. Rows can also be used on -vertically docked panes. - -**Layer** - A layer is akin to an onion. Layer 0 is the very center of the managed pane. -Thus, if a pane is in layer 0, it will be closest to the center window (also sometimes -known as the "content window"). Increasing layers "swallow up" all layers of a lower -value. This can look very similar to multiple rows, but is different because all panes -in a lower level yield to panes in higher levels. The best way to understand layers -is by running the AUI sample (`AUI.py`). -""" - -__author__ = "Andrea Gavana " -__date__ = "31 March 2009" - - -import wx -import time -import types -import warnings - -import auibar -import auibook -import tabmdi -import dockart -import tabart - -from aui_utilities import Clip, PaneCreateStippleBitmap, GetDockingImage, GetSlidingPoints - -from aui_constants import * - -# Define this as a translation function -_ = wx.GetTranslation - -_winxptheme = False -if wx.Platform == "__WXMSW__": - try: - import winxptheme - _winxptheme = True - except ImportError: - pass - -# wxPython version string -_VERSION_STRING = wx.VERSION_STRING - -# AUI Events -wxEVT_AUI_PANE_BUTTON = wx.NewEventType() -wxEVT_AUI_PANE_CLOSE = wx.NewEventType() -wxEVT_AUI_PANE_MAXIMIZE = wx.NewEventType() -wxEVT_AUI_PANE_RESTORE = wx.NewEventType() -wxEVT_AUI_RENDER = wx.NewEventType() -wxEVT_AUI_FIND_MANAGER = wx.NewEventType() -wxEVT_AUI_PANE_MINIMIZE = wx.NewEventType() -wxEVT_AUI_PANE_MIN_RESTORE = wx.NewEventType() -wxEVT_AUI_PANE_FLOATING = wx.NewEventType() -wxEVT_AUI_PANE_FLOATED = wx.NewEventType() -wxEVT_AUI_PANE_DOCKING = wx.NewEventType() -wxEVT_AUI_PANE_DOCKED = wx.NewEventType() -wxEVT_AUI_PANE_ACTIVATED = wx.NewEventType() -wxEVT_AUI_PERSPECTIVE_CHANGED = wx.NewEventType() - -EVT_AUI_PANE_BUTTON = wx.PyEventBinder(wxEVT_AUI_PANE_BUTTON, 0) -""" Fires an event when the user left-clicks on a pane button. """ -EVT_AUI_PANE_CLOSE = wx.PyEventBinder(wxEVT_AUI_PANE_CLOSE, 0) -""" A pane in `AuiManager` has been closed. """ -EVT_AUI_PANE_MAXIMIZE = wx.PyEventBinder(wxEVT_AUI_PANE_MAXIMIZE, 0) -""" A pane in `AuiManager` has been maximized. """ -EVT_AUI_PANE_RESTORE = wx.PyEventBinder(wxEVT_AUI_PANE_RESTORE, 0) -""" A pane in `AuiManager` has been restored from a maximized state. """ -EVT_AUI_RENDER = wx.PyEventBinder(wxEVT_AUI_RENDER, 0) -""" Fires an event every time the AUI frame is being repainted. """ -EVT_AUI_FIND_MANAGER = wx.PyEventBinder(wxEVT_AUI_FIND_MANAGER, 0) -""" Used to find which AUI manager is controlling a certain pane. """ -EVT_AUI_PANE_MINIMIZE = wx.PyEventBinder(wxEVT_AUI_PANE_MINIMIZE, 0) -""" A pane in `AuiManager` has been minimized. """ -EVT_AUI_PANE_MIN_RESTORE = wx.PyEventBinder(wxEVT_AUI_PANE_MIN_RESTORE, 0) -""" A pane in `AuiManager` has been restored from a minimized state. """ -EVT_AUI_PANE_FLOATING = wx.PyEventBinder(wxEVT_AUI_PANE_FLOATING, 0) -""" A pane in `AuiManager` is about to be floated. """ -EVT_AUI_PANE_FLOATED = wx.PyEventBinder(wxEVT_AUI_PANE_FLOATED, 0) -""" A pane in `AuiManager` has been floated. """ -EVT_AUI_PANE_DOCKING = wx.PyEventBinder(wxEVT_AUI_PANE_DOCKING, 0) -""" A pane in `AuiManager` is about to be docked. """ -EVT_AUI_PANE_DOCKED = wx.PyEventBinder(wxEVT_AUI_PANE_DOCKED, 0) -""" A pane in `AuiManager` has been docked. """ -EVT_AUI_PANE_ACTIVATED = wx.PyEventBinder(wxEVT_AUI_PANE_ACTIVATED, 0) -""" A pane in `AuiManager` has been activated. """ -EVT_AUI_PERSPECTIVE_CHANGED = wx.PyEventBinder(wxEVT_AUI_PERSPECTIVE_CHANGED, 0) -""" The layout in `AuiManager` has been changed. """ - -# ---------------------------------------------------------------------------- # - -class AuiDockInfo(object): - """ A class to store all properties of a dock. """ - - def __init__(self): - """ - Default class constructor. - Used internally, do not call it in your code! - """ - - object.__init__(self) - - self.dock_direction = 0 - self.dock_layer = 0 - self.dock_row = 0 - self.size = 0 - self.min_size = 0 - self.resizable = True - self.fixed = False - self.toolbar = False - self.rect = wx.Rect() - self.panes = [] - - - def IsOk(self): - """ - Returns whether a dock is valid or not. - - In order to be valid, a dock needs to have a non-zero `dock_direction`. - """ - - return self.dock_direction != 0 - - - def IsHorizontal(self): - """ Returns whether the dock is horizontal or not. """ - - return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM] - - - def IsVertical(self): - """ Returns whether the dock is vertical or not. """ - - return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER] - - -# ---------------------------------------------------------------------------- # - -class AuiDockingGuideInfo(object): - """ A class which holds information about VS2005 docking guide windows. """ - - def __init__(self, other=None): - """ - Default class constructor. - Used internally, do not call it in your code! - - :param `other`: another instance of :class:`AuiDockingGuideInfo`. - """ - - if other: - self.Assign(other) - else: - # window representing the docking target - self.host = None - # dock direction (top, bottom, left, right, center) - self.dock_direction = AUI_DOCK_NONE - - - def Assign(self, other): - """ - Assigns the properties of the `other` :class:`AuiDockingGuideInfo` to `self`. - - :param `other`: another instance of :class:`AuiDockingGuideInfo`. - """ - - self.host = other.host - self.dock_direction = other.dock_direction - - - def Host(self, h): - """ - Hosts a docking guide window. - - :param `h`: an instance of :class:`AuiDockingGuideWindow` or :class:`AuiDockingHintWindow`. - """ - - self.host = h - return self - - - def Left(self): - """ Sets the guide window to left docking. """ - - self.dock_direction = AUI_DOCK_LEFT - return self - - - def Right(self): - """ Sets the guide window to right docking. """ - - self.dock_direction = AUI_DOCK_RIGHT - return self - - - def Top(self): - """ Sets the guide window to top docking. """ - - self.dock_direction = AUI_DOCK_TOP - return self - - - def Bottom(self): - """ Sets the guide window to bottom docking. """ - - self.dock_direction = AUI_DOCK_BOTTOM - return self - - - def Center(self): - """ Sets the guide window to center docking. """ - - self.dock_direction = AUI_DOCK_CENTER - return self - - - def Centre(self): - """ Sets the guide window to centre docking. """ - - self.dock_direction = AUI_DOCK_CENTRE - return self - - -# ---------------------------------------------------------------------------- # - -class AuiDockUIPart(object): - """ A class which holds attributes for a UI part in the interface. """ - - typeCaption = 0 - typeGripper = 1 - typeDock = 2 - typeDockSizer = 3 - typePane = 4 - typePaneSizer = 5 - typeBackground = 6 - typePaneBorder = 7 - typePaneButton = 8 - - def __init__(self): - """ - Default class constructor. - Used internally, do not call it in your code! - """ - - self.orientation = wx.VERTICAL - self.type = 0 - self.rect = wx.Rect() - - -# ---------------------------------------------------------------------------- # - -class AuiPaneButton(object): - """ A simple class which describes the caption pane button attributes. """ - - def __init__(self, button_id): - """ - Default class constructor. - Used internally, do not call it in your code! - - :param integer `button_id`: the pane button identifier. - """ - - self.button_id = button_id - - -# ---------------------------------------------------------------------------- # - -# event declarations/classes - -class AuiManagerEvent(wx.PyCommandEvent): - """ A specialized command event class for events sent by :class:`AuiManager`. """ - - def __init__(self, eventType, id=1): - """ - Default class constructor. - - :param integer `eventType`: the event kind; - :param integer `id`: the event identification number. - """ - - wx.PyCommandEvent.__init__(self, eventType, id) - - self.manager = None - self.pane = None - self.button = 0 - self.veto_flag = False - self.canveto_flag = True - self.dc = None - - - def SetManager(self, mgr): - """ - Associates a :class:`AuiManager` to the current event. - - :param `mgr`: an instance of :class:`AuiManager`. - """ - - self.manager = mgr - - - def SetDC(self, pdc): - """ - Associates a :class:`DC` device context to this event. - - :param `pdc`: a :class:`DC` device context object. - """ - - self.dc = pdc - - - def SetPane(self, p): - """ - Associates a :class:`AuiPaneInfo` instance to this event. - - :param `p`: a :class:`AuiPaneInfo` instance. - """ - - self.pane = p - - - def SetButton(self, b): - """ - Associates a :class:`AuiPaneButton` instance to this event. - - :param `b`: a :class:`AuiPaneButton` instance. - """ - - self.button = b - - - def GetManager(self): - """ Returns the associated :class:`AuiManager` (if any). """ - - return self.manager - - - def GetDC(self): - """ Returns the associated :class:`DC` device context (if any). """ - - return self.dc - - - def GetPane(self): - """ Returns the associated :class:`AuiPaneInfo` structure (if any). """ - - return self.pane - - - def GetButton(self): - """ Returns the associated :class:`AuiPaneButton` instance (if any). """ - - return self.button - - - def Veto(self, veto=True): - """ - Prevents the change announced by this event from happening. - - It is in general a good idea to notify the user about the reasons for - vetoing the change because otherwise the applications behaviour (which - just refuses to do what the user wants) might be quite surprising. - - :param bool `veto`: ``True`` to veto the event, ``False`` otherwise. - """ - - self.veto_flag = veto - - - def GetVeto(self): - """ Returns whether the event has been vetoed or not. """ - - return self.veto_flag - - - def SetCanVeto(self, can_veto): - """ - Sets whether the event can be vetoed or not. - - :param bool `can_veto`: ``True`` if the event can be vetoed, ``False`` otherwise. - """ - - self.canveto_flag = can_veto - - - def CanVeto(self): - """ Returns whether the event can be vetoed and has been vetoed. """ - - return self.canveto_flag and self.veto_flag - - -# ---------------------------------------------------------------------------- # - -class AuiPaneInfo(object): - """ - AuiPaneInfo specifies all the parameters for a pane. These parameters specify where - the pane is on the screen, whether it is docked or floating, or hidden. In addition, - these parameters specify the pane's docked position, floating position, preferred - size, minimum size, caption text among many other parameters. - """ - - optionFloating = 2**0 - optionHidden = 2**1 - optionLeftDockable = 2**2 - optionRightDockable = 2**3 - optionTopDockable = 2**4 - optionBottomDockable = 2**5 - optionFloatable = 2**6 - optionMovable = 2**7 - optionResizable = 2**8 - optionPaneBorder = 2**9 - optionCaption = 2**10 - optionGripper = 2**11 - optionDestroyOnClose = 2**12 - optionToolbar = 2**13 - optionActive = 2**14 - optionGripperTop = 2**15 - optionMaximized = 2**16 - optionDockFixed = 2**17 - optionNotebookDockable = 2**18 - optionMinimized = 2**19 - optionLeftSnapped = 2**20 - optionRightSnapped = 2**21 - optionTopSnapped = 2**22 - optionBottomSnapped = 2**23 - optionFlyOut = 2**24 - optionCaptionLeft = 2**25 - - buttonClose = 2**26 - buttonMaximize = 2**27 - buttonMinimize = 2**28 - buttonPin = 2**29 - - buttonCustom1 = 2**30 - buttonCustom2 = 2**31 - buttonCustom3 = 2**32 - - savedHiddenState = 2**33 # used internally - actionPane = 2**34 # used internally - wasMaximized = 2**35 # used internally - needsRestore = 2**36 # used internally - - - def __init__(self): - """ Default class constructor. """ - - self.window = None - self.frame = None - self.state = 0 - self.dock_direction = AUI_DOCK_LEFT - self.dock_layer = 0 - self.dock_row = 0 - self.dock_pos = 0 - self.minimize_mode = AUI_MINIMIZE_POS_SMART - self.floating_pos = wx.Point(-1, -1) - self.floating_size = wx.Size(-1, -1) - self.best_size = wx.Size(-1, -1) - self.min_size = wx.Size(-1, -1) - self.max_size = wx.Size(-1, -1) - self.dock_proportion = 0 - self.caption = "" - self.buttons = [] - self.name = "" - self.icon = wx.NullIcon - self.rect = wx.Rect() - self.notebook_id = -1 - self.transparent = 255 - self.needsTransparency = False - self.previousDockPos = None - self.previousDockSize = 0 - self.snapped = 0 - self.minimize_target = None - - self.DefaultPane() - - - def dock_direction_get(self): - """ - Getter for the `dock_direction`. - - :see: :meth:`~AuiPaneInfo.dock_direction_set` for a set of valid docking directions. - """ - - if self.IsMaximized(): - return AUI_DOCK_CENTER - else: - return self._dock_direction - - - def dock_direction_set(self, value): - """ - Setter for the `dock_direction`. - - :param integer `value`: the docking direction. This can be one of the following bits: - - ============================ ======= ============================================= - Dock Flag Value Description - ============================ ======= ============================================= - ``AUI_DOCK_NONE`` 0 No docking direction. - ``AUI_DOCK_TOP`` 1 Top docking direction. - ``AUI_DOCK_RIGHT`` 2 Right docking direction. - ``AUI_DOCK_BOTTOM`` 3 Bottom docking direction. - ``AUI_DOCK_LEFT`` 4 Left docking direction. - ``AUI_DOCK_CENTER`` 5 Center docking direction. - ``AUI_DOCK_CENTRE`` 5 Centre docking direction. - ``AUI_DOCK_NOTEBOOK_PAGE`` 6 Automatic AuiNotebooks docking style. - ============================ ======= ============================================= - - """ - - self._dock_direction = value - - dock_direction = property(dock_direction_get, dock_direction_set) - - def IsOk(self): - """ - Returns ``True`` if the :class:`AuiPaneInfo` structure is valid. - - :note: A pane structure is valid if it has an associated window. - """ - - return self.window != None - - - def IsMaximized(self): - """ Returns ``True`` if the pane is maximized. """ - - return self.HasFlag(self.optionMaximized) - - - def IsMinimized(self): - """ Returns ``True`` if the pane is minimized. """ - - return self.HasFlag(self.optionMinimized) - - - def IsFixed(self): - """ Returns ``True`` if the pane cannot be resized. """ - - return not self.HasFlag(self.optionResizable) - - - def IsResizeable(self): - """ Returns ``True`` if the pane can be resized. """ - - return self.HasFlag(self.optionResizable) - - - def IsShown(self): - """ Returns ``True`` if the pane is currently shown. """ - - return not self.HasFlag(self.optionHidden) - - - def IsFloating(self): - """ Returns ``True`` if the pane is floating. """ - - return self.HasFlag(self.optionFloating) - - - def IsDocked(self): - """ Returns ``True`` if the pane is docked. """ - - return not self.HasFlag(self.optionFloating) - - - def IsToolbar(self): - """ Returns ``True`` if the pane contains a toolbar. """ - - return self.HasFlag(self.optionToolbar) - - - def IsTopDockable(self): - """ - Returns ``True`` if the pane can be docked at the top - of the managed frame. - """ - - return self.HasFlag(self.optionTopDockable) - - - def IsBottomDockable(self): - """ - Returns ``True`` if the pane can be docked at the bottom - of the managed frame. - """ - - return self.HasFlag(self.optionBottomDockable) - - - def IsLeftDockable(self): - """ - Returns ``True`` if the pane can be docked at the left - of the managed frame. - """ - - return self.HasFlag(self.optionLeftDockable) - - - def IsRightDockable(self): - """ - Returns ``True`` if the pane can be docked at the right - of the managed frame. - """ - - return self.HasFlag(self.optionRightDockable) - - - def IsDockable(self): - """ Returns ``True`` if the pane can be docked. """ - - return self.IsTopDockable() or self.IsBottomDockable() or self.IsLeftDockable() or \ - self.IsRightDockable() or self.IsNotebookDockable() - - - def IsFloatable(self): - """ - Returns ``True`` if the pane can be undocked and displayed as a - floating window. - """ - - return self.HasFlag(self.optionFloatable) - - - def IsMovable(self): - """ - Returns ``True`` if the docked frame can be undocked or moved to - another dock position. - """ - - return self.HasFlag(self.optionMovable) - - - def IsDestroyOnClose(self): - """ - Returns ``True`` if the pane should be destroyed when it is closed. - - Normally a pane is simply hidden when the close button is clicked. Calling :meth:`~AuiPaneInfo.DestroyOnClose` - with a ``True`` input parameter will cause the window to be destroyed when the user clicks - the pane's close button. - """ - - return self.HasFlag(self.optionDestroyOnClose) - - - def IsNotebookDockable(self): - """ - Returns ``True`` if a pane can be docked on top to another to create a - :class:`~lib.agw.aui.auibook.AuiNotebook`. - """ - - return self.HasFlag(self.optionNotebookDockable) - - - def IsTopSnappable(self): - """ Returns ``True`` if the pane can be snapped at the top of the managed frame. """ - - return self.HasFlag(self.optionTopSnapped) - - - def IsBottomSnappable(self): - """ Returns ``True`` if the pane can be snapped at the bottom of the managed frame. """ - - return self.HasFlag(self.optionBottomSnapped) - - - def IsLeftSnappable(self): - """ Returns ``True`` if the pane can be snapped on the left of the managed frame. """ - - return self.HasFlag(self.optionLeftSnapped) - - - def IsRightSnappable(self): - """ Returns ``True`` if the pane can be snapped on the right of the managed frame. """ - - return self.HasFlag(self.optionRightSnapped) - - - def IsSnappable(self): - """ Returns ``True`` if the pane can be snapped. """ - - return self.IsTopSnappable() or self.IsBottomSnappable() or self.IsLeftSnappable() or \ - self.IsRightSnappable() - - - def IsFlyOut(self): - """ Returns ``True`` if the floating pane has a "fly-out" effect. """ - - return self.HasFlag(self.optionFlyOut) - - - def HasCaption(self): - """ Returns ``True`` if the pane displays a caption. """ - - return self.HasFlag(self.optionCaption) - - - def HasCaptionLeft(self): - """ Returns ``True`` if the pane displays a caption on the left (rotated by 90 degrees). """ - - return self.HasFlag(self.optionCaptionLeft) - - - def HasGripper(self): - """ Returns ``True`` if the pane displays a gripper. """ - - return self.HasFlag(self.optionGripper) - - - def HasBorder(self): - """ Returns ``True`` if the pane displays a border. """ - - return self.HasFlag(self.optionPaneBorder) - - - def HasCloseButton(self): - """ Returns ``True`` if the pane displays a button to close the pane. """ - - return self.HasFlag(self.buttonClose) - - - def HasMaximizeButton(self): - """ Returns ``True`` if the pane displays a button to maximize the pane. """ - - return self.HasFlag(self.buttonMaximize) - - - def HasMinimizeButton(self): - """ Returns ``True`` if the pane displays a button to minimize the pane. """ - - return self.HasFlag(self.buttonMinimize) - - - def GetMinimizeMode(self): - """ - Returns the minimization style for this pane. - - Possible return values are: - - ============================== ========= ============================== - Minimize Mode Flag Hex Value Description - ============================== ========= ============================== - ``AUI_MINIMIZE_POS_SMART`` 0x01 Minimizes the pane on the closest tool bar - ``AUI_MINIMIZE_POS_TOP`` 0x02 Minimizes the pane on the top tool bar - ``AUI_MINIMIZE_POS_LEFT`` 0x03 Minimizes the pane on its left tool bar - ``AUI_MINIMIZE_POS_RIGHT`` 0x04 Minimizes the pane on its right tool bar - ``AUI_MINIMIZE_POS_BOTTOM`` 0x05 Minimizes the pane on its bottom tool bar - ``AUI_MINIMIZE_POS_TOOLBAR`` 0x06 Minimizes the pane on a target :class:`~lib.agw.aui.auibar.AuiToolBar` - ``AUI_MINIMIZE_POS_MASK`` 0x17 Mask to filter the position flags - ``AUI_MINIMIZE_CAPT_HIDE`` 0x0 Hides the caption of the minimized pane - ``AUI_MINIMIZE_CAPT_SMART`` 0x08 Displays the caption in the best rotation (horizontal or clockwise) - ``AUI_MINIMIZE_CAPT_HORZ`` 0x10 Displays the caption horizontally - ``AUI_MINIMIZE_CAPT_MASK`` 0x18 Mask to filter the caption flags - ============================== ========= ============================== - - The flags can be filtered with the following masks: - - ============================== ========= ============================== - Minimize Mask Flag Hex Value Description - ============================== ========= ============================== - ``AUI_MINIMIZE_POS_MASK`` 0x17 Filters the position flags - ``AUI_MINIMIZE_CAPT_MASK`` 0x18 Filters the caption flags - ============================== ========= ============================== - - """ - - return self.minimize_mode - - - def HasPinButton(self): - """ Returns ``True`` if the pane displays a button to float the pane. """ - - return self.HasFlag(self.buttonPin) - - - def HasGripperTop(self): - """ Returns ``True`` if the pane displays a gripper at the top. """ - - return self.HasFlag(self.optionGripperTop) - - - def Window(self, w): - """ - Associate a :class:`Window` derived window to this pane. - - This normally does not need to be specified, as the window pointer is - automatically assigned to the :class:`AuiPaneInfo` structure as soon as it is - added to the manager. - - :param `w`: a :class:`Window` derived window. - """ - - self.window = w - return self - - - def Name(self, name): - """ - Sets the name of the pane so it can be referenced in lookup functions. - - If a name is not specified by the user, a random name is assigned to the pane - when it is added to the manager. - - :param `name`: a string specifying the pane name. - - .. warning:: - - If you are using :meth:`AuiManager.SavePerspective` and :meth:`AuiManager.LoadPerspective`, - you will have to specify a name for your pane using :meth:`~AuiPaneInfo.Name`, as perspectives - containing randomly generated names can not be properly restored. - """ - - self.name = name - return self - - - def Caption(self, caption): - """ - Sets the caption of the pane. - - :param string `caption`: a string specifying the pane caption. - """ - - self.caption = caption - return self - - - def Left(self): - """ - Sets the pane dock position to the left side of the frame. - - :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_LEFT`` as - parameter. - """ - - self.dock_direction = AUI_DOCK_LEFT - return self - - - def Right(self): - """ - Sets the pane dock position to the right side of the frame. - - :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_RIGHT`` as - parameter. - """ - - self.dock_direction = AUI_DOCK_RIGHT - return self - - - def Top(self): - """ - Sets the pane dock position to the top of the frame. - - :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_TOP`` as - parameter. - """ - - self.dock_direction = AUI_DOCK_TOP - return self - - - def Bottom(self): - """ - Sets the pane dock position to the bottom of the frame. - - :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_BOTTOM`` as - parameter. - """ - - self.dock_direction = AUI_DOCK_BOTTOM - return self - - - def Center(self): - """ - Sets the pane to the center position of the frame. - - The centre pane is the space in the middle after all border panes (left, top, - right, bottom) are subtracted from the layout. - - :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_CENTER`` as - parameter. - """ - - self.dock_direction = AUI_DOCK_CENTER - return self - - - def Centre(self): - """ - Sets the pane to the center position of the frame. - - The centre pane is the space in the middle after all border panes (left, top, - right, bottom) are subtracted from the layout. - - :note: This is the same thing as calling :meth:`~AuiPaneInfo.Direction` with ``AUI_DOCK_CENTRE`` as - parameter. - """ - - self.dock_direction = AUI_DOCK_CENTRE - return self - - - def Direction(self, direction): - """ - Determines the direction of the docked pane. It is functionally the - same as calling :meth:`Left`, :meth:`Right`, :meth:`Top` or :meth:`Bottom`, - except that docking direction may be specified programmatically via the parameter `direction`. - - :param integer `direction`: the direction of the docked pane. - - :see: :meth:`dock_direction_set` for a list of valid docking directions. - """ - - self.dock_direction = direction - return self - - - def Layer(self, layer): - """ - Determines the layer of the docked pane. - - The dock layer is similar to an onion, the inner-most layer being layer 0. Each - shell moving in the outward direction has a higher layer number. This allows for - more complex docking layout formation. - - :param integer `layer`: the layer of the docked pane. - """ - - self.dock_layer = layer - return self - - - def Row(self, row): - """ - Determines the row of the docked pane. - - :param integer `row`: the row of the docked pane. - """ - - self.dock_row = row - return self - - - def Position(self, pos): - """ - Determines the position of the docked pane. - - :param integer `pos`: the position of the docked pane. - """ - - self.dock_pos = pos - return self - - - def MinSize(self, arg1=None, arg2=None): - """ - Sets the minimum size of the pane. - - This method is split in 2 versions depending on the input type. If `arg1` is - a :class:`Size` object, then :meth:`~AuiPaneInfo.MinSize1` is called. Otherwise, :meth:`~AuiPaneInfo.MinSize2` is called. - - :param `arg1`: a :class:`Size` object, a (x, y) tuple or or a `x` coordinate. - :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused). - """ - - if isinstance(arg1, wx.Size): - ret = self.MinSize1(arg1) - elif isinstance(arg1, types.TupleType): - ret = self.MinSize1(wx.Size(*arg1)) - elif isinstance(arg1, types.IntType) and arg2 is not None: - ret = self.MinSize2(arg1, arg2) - else: - raise Exception("Invalid argument passed to `MinSize`: arg1=%s, arg2=%s"%(repr(arg1), repr(arg2))) - - return ret - - - def MinSize1(self, size): - """ - Sets the minimum size of the pane. - - :see: :meth:`MinSize` for an explanation of input parameters. - """ - self.min_size = size - return self - - - def MinSize2(self, x, y): - """ - Sets the minimum size of the pane. - - :see: :meth:`MinSize` for an explanation of input parameters. - """ - - self.min_size = wx.Size(x, y) - return self - - - def MaxSize(self, arg1=None, arg2=None): - """ - Sets the maximum size of the pane. - - This method is split in 2 versions depending on the input type. If `arg1` is - a :class:`Size` object, then :meth:`~AuiPaneInfo.MaxSize1` is called. Otherwise, :meth:`~AuiPaneInfo.MaxSize2` is called. - - :param `arg1`: a :class:`Size` object, a (x, y) tuple or a `x` coordinate. - :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused). - """ - - if isinstance(arg1, wx.Size): - ret = self.MaxSize1(arg1) - elif isinstance(arg1, types.TupleType): - ret = self.MaxSize1(wx.Size(*arg1)) - elif isinstance(arg1, types.IntType) and arg2 is not None: - ret = self.MaxSize2(arg1, arg2) - else: - raise Exception("Invalid argument passed to `MaxSize`: arg1=%s, arg2=%s"%(repr(arg1), repr(arg2))) - - return ret - - - def MaxSize1(self, size): - """ - Sets the maximum size of the pane. - - :see: :meth:`MaxSize` for an explanation of input parameters. - """ - - self.max_size = size - return self - - - def MaxSize2(self, x, y): - """ - Sets the maximum size of the pane. - - :see: :meth:`MaxSize` for an explanation of input parameters. - """ - - self.max_size.Set(x,y) - return self - - - def BestSize(self, arg1=None, arg2=None): - """ - Sets the ideal size for the pane. The docking manager will attempt to use - this size as much as possible when docking or floating the pane. - - This method is split in 2 versions depending on the input type. If `arg1` is - a :class:`Size` object, then :meth:`BestSize1` is called. Otherwise, :meth:`BestSize2` is called. - - :param `arg1`: a :class:`Size` object, a (x, y) tuple or a `x` coordinate. - :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused). - """ - - if isinstance(arg1, wx.Size): - ret = self.BestSize1(arg1) - elif isinstance(arg1, types.TupleType): - ret = self.BestSize1(wx.Size(*arg1)) - elif isinstance(arg1, types.IntType) and arg2 is not None: - ret = self.BestSize2(arg1, arg2) - else: - raise Exception("Invalid argument passed to `BestSize`: arg1=%s, arg2=%s"%(repr(arg1), repr(arg2))) - - return ret - - - def BestSize1(self, size): - """ - Sets the best size of the pane. - - :see: :meth:`BestSize` for an explanation of input parameters. - """ - - self.best_size = size - return self - - - def BestSize2(self, x, y): - """ - Sets the best size of the pane. - - :see: :meth:`BestSize` for an explanation of input parameters. - """ - - self.best_size.Set(x,y) - return self - - - def FloatingPosition(self, pos): - """ - Sets the position of the floating pane. - - :param `pos`: a :class:`Point` or a tuple indicating the pane floating position. - """ - - self.floating_pos = wx.Point(*pos) - return self - - - def FloatingSize(self, size): - """ - Sets the size of the floating pane. - - :param `size`: a :class:`Size` or a tuple indicating the pane floating size. - """ - - self.floating_size = wx.Size(*size) - return self - - - def Maximize(self): - """ Makes the pane take up the full area.""" - - return self.SetFlag(self.optionMaximized, True) - - - def Minimize(self): - """ - Makes the pane minimized in a :class:`~lib.agw.aui.auibar.AuiToolBar`. - - Clicking on the minimize button causes a new :class:`~lib.agw.aui.auibar.AuiToolBar` to be created - and added to the frame manager, (currently the implementation is such that - panes at West will have a toolbar at the right, panes at South will have - toolbars at the bottom etc...) and the pane is hidden in the manager. - - Clicking on the restore button on the newly created toolbar will result in the - toolbar being removed and the original pane being restored. - """ - - return self.SetFlag(self.optionMinimized, True) - - - def MinimizeMode(self, mode): - """ - Sets the expected minimized mode if the minimize button is visible. - - :param integer `mode`: the minimized pane can have a specific position in the work space: - - ============================== ========= ============================== - Minimize Mode Flag Hex Value Description - ============================== ========= ============================== - ``AUI_MINIMIZE_POS_SMART`` 0x01 Minimizes the pane on the closest tool bar - ``AUI_MINIMIZE_POS_TOP`` 0x02 Minimizes the pane on the top tool bar - ``AUI_MINIMIZE_POS_LEFT`` 0x03 Minimizes the pane on its left tool bar - ``AUI_MINIMIZE_POS_RIGHT`` 0x04 Minimizes the pane on its right tool bar - ``AUI_MINIMIZE_POS_BOTTOM`` 0x05 Minimizes the pane on its bottom tool bar - ``AUI_MINIMIZE_POS_TOOLBAR`` 0x06 Minimizes the pane on a target :class:`~lib.agw.aui.auibar.AuiToolBar` - ============================== ========= ============================== - - The caption of the minimized pane can be displayed in different modes: - - ============================== ========= ============================== - Caption Mode Flag Hex Value Description - ============================== ========= ============================== - ``AUI_MINIMIZE_CAPT_HIDE`` 0x0 Hides the caption of the minimized pane - ``AUI_MINIMIZE_CAPT_SMART`` 0x08 Displays the caption in the best rotation (horizontal in the top and in - the bottom tool bar or clockwise in the right and in the left tool bar) - ``AUI_MINIMIZE_CAPT_HORZ`` 0x10 Displays the caption horizontally - ============================== ========= ============================== - - .. note:: - - In order to use the ``AUI_MINIMIZE_POS_TOOLBAR`` flag, the instance of :class:`AuiManager` - you pass as an input for :meth:`MinimizeTarget` **must** have a real name and not the randomly - generated one. Remember to set the :meth:`Name` property of the toolbar pane before calling this method. - - """ - - self.minimize_mode = mode - return self - - - def MinimizeTarget(self, toolbarPane): - """ - Minimizes the panes using a :class:`AuiPaneInfo` as a target. As :class:`AuiPaneInfo` properties - need to be copied back and forth every time the perspective has changed, we - only store the toobar **name**. - - :param `toolbarPane`: an instance of :class:`AuiPaneInfo`, containing a :class:`~lib.agw.aui.auibar.AuiToolBar`. - - .. note:: - - In order to use this functionality (and with the ``AUI_MINIMIZE_POS_TOOLBAR`` - flag set), the instance of :class:`AuiPaneInfo` you pass as an input **must** have a real - name and not the randomly generated one. Remember to set the :meth:`Name` property of - the toolbar pane before calling this method. - - """ - - self.minimize_target = toolbarPane.name - return self - - - def Restore(self): - """ Is the reverse of :meth:`Maximize` and :meth:`Minimize`.""" - - return self.SetFlag(self.optionMaximized or self.optionMinimized, False) - - - def Fixed(self): - """ - Forces a pane to be fixed size so that it cannot be resized. - After calling :meth:`Fixed`, :meth:`IsFixed` will return ``True``. - """ - - return self.SetFlag(self.optionResizable, False) - - - def Resizable(self, resizable=True): - """ - Allows a pane to be resizable if `resizable` is ``True``, and forces - it to be a fixed size if `resizeable` is ``False``. - - If `resizable` is ``False``, this is simply an antonym for :meth:`Fixed`. - - :param bool `resizable`: whether the pane will be resizeable or not. - """ - - return self.SetFlag(self.optionResizable, resizable) - - - def Transparent(self, alpha): - """ - Makes the pane transparent when floating. - - :param integer `alpha`: a value between 0 and 255 for pane transparency. - """ - - if alpha < 0 or alpha > 255: - raise Exception("Invalid transparency value (%s)"%repr(alpha)) - - self.transparent = alpha - self.needsTransparency = True - - - def Dock(self): - """ Indicates that a pane should be docked. It is the opposite of :meth:`Float`. """ - - if self.IsNotebookPage(): - self.notebook_id = -1 - self.dock_direction = AUI_DOCK_NONE - - return self.SetFlag(self.optionFloating, False) - - - def Float(self): - """ Indicates that a pane should be floated. It is the opposite of :meth:`Dock`. """ - - if self.IsNotebookPage(): - self.notebook_id = -1 - self.dock_direction = AUI_DOCK_NONE - - return self.SetFlag(self.optionFloating, True) - - - def Hide(self): - """ - Indicates that a pane should be hidden. - - Calling :meth:`Show(False) ` achieve the same effect. - """ - - return self.SetFlag(self.optionHidden, True) - - - def Show(self, show=True): - """ - Indicates that a pane should be shown. - - :param bool `show`: whether the pane should be shown or not. - """ - - return self.SetFlag(self.optionHidden, not show) - - - # By defaulting to 1000, the tab will get placed at the end - def NotebookPage(self, id, tab_position=1000): - """ - Forces a pane to be a notebook page, so that the pane can be - docked on top to another to create a :class:`~lib.agw.aui.auibook.AuiNotebook`. - - :param integer `id`: the notebook id; - :param integer `tab_position`: the tab number of the pane once docked in a notebook. - """ - - # Remove any floating frame - self.Dock() - self.notebook_id = id - self.dock_pos = tab_position - self.dock_row = 0 - self.dock_layer = 0 - self.dock_direction = AUI_DOCK_NOTEBOOK_PAGE - - return self - - - def NotebookControl(self, id): - """ - Forces a pane to be a notebook control (:class:`~lib.agw.aui.auibook.AuiNotebook`). - - :param integer `id`: the notebook id. - """ - - self.notebook_id = id - self.window = None - self.buttons = [] - - if self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE: - self.dock_direction = AUI_DOCK_NONE - - return self - - - def HasNotebook(self): - """ Returns whether a pane has a :class:`~lib.agw.aui.auibook.AuiNotebook` or not. """ - - return self.notebook_id >= 0 - - - def IsNotebookPage(self): - """ Returns whether the pane is a notebook page in a :class:`~lib.agw.aui.auibook.AuiNotebook`. """ - - return self.notebook_id >= 0 and self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE - - - def IsNotebookControl(self): - """ Returns whether the pane is a notebook control (:class:`~lib.agw.aui.auibook.AuiNotebook`). """ - - return not self.IsNotebookPage() and self.HasNotebook() - - - def SetNameFromNotebookId(self): - """ Sets the pane name once docked in a :class:`~lib.agw.aui.auibook.AuiNotebook` using the notebook id. """ - - if self.notebook_id >= 0: - self.name = "__notebook_%d"%self.notebook_id - - return self - - - def CaptionVisible(self, visible=True, left=False): - """ - Indicates that a pane caption should be visible. If `visible` is ``False``, no pane - caption is drawn. - - :param bool `visible`: whether the caption should be visible or not; - :param bool `left`: whether the caption should be drawn on the left (rotated by 90 degrees) or not. - """ - - if left: - self.SetFlag(self.optionCaption, False) - return self.SetFlag(self.optionCaptionLeft, visible) - - self.SetFlag(self.optionCaptionLeft, False) - return self.SetFlag(self.optionCaption, visible) - - - def PaneBorder(self, visible=True): - """ - Indicates that a border should be drawn for the pane. - - :param bool `visible`: whether the pane border should be visible or not. - """ - - return self.SetFlag(self.optionPaneBorder, visible) - - - def Gripper(self, visible=True): - """ - Indicates that a gripper should be drawn for the pane. - - :param bool `visible`: whether the gripper should be visible or not. - """ - - return self.SetFlag(self.optionGripper, visible) - - - def GripperTop(self, attop=True): - """ - Indicates that a gripper should be drawn at the top of the pane. - - :param bool `attop`: whether the gripper should be drawn at the top or not. - """ - - return self.SetFlag(self.optionGripperTop, attop) - - - def CloseButton(self, visible=True): - """ - Indicates that a close button should be drawn for the pane. - - :param bool `visible`: whether the close button should be visible or not. - """ - - return self.SetFlag(self.buttonClose, visible) - - - def MaximizeButton(self, visible=True): - """ - Indicates that a maximize button should be drawn for the pane. - - :param bool `visible`: whether the maximize button should be visible or not. - """ - - return self.SetFlag(self.buttonMaximize, visible) - - - def MinimizeButton(self, visible=True): - """ - Indicates that a minimize button should be drawn for the pane. - - :param bool `visible`: whether the minimize button should be visible or not. - """ - - return self.SetFlag(self.buttonMinimize, visible) - - - def PinButton(self, visible=True): - """ - Indicates that a pin button should be drawn for the pane. - - :param bool `visible`: whether the pin button should be visible or not. - """ - - return self.SetFlag(self.buttonPin, visible) - - - def DestroyOnClose(self, b=True): - """ - Indicates whether a pane should be destroyed when it is closed. - - Normally a pane is simply hidden when the close button is clicked. Setting - `b` to ``True`` will cause the window to be destroyed when the user clicks - the pane's close button. - - :param bool `b`: whether the pane should be destroyed when it is closed or not. - """ - - return self.SetFlag(self.optionDestroyOnClose, b) - - - def TopDockable(self, b=True): - """ - Indicates whether a pane can be docked at the top of the frame. - - :param bool `b`: whether the pane can be docked at the top or not. - """ - - return self.SetFlag(self.optionTopDockable, b) - - - def BottomDockable(self, b=True): - """ - Indicates whether a pane can be docked at the bottom of the frame. - - :param bool `b`: whether the pane can be docked at the bottom or not. - """ - - return self.SetFlag(self.optionBottomDockable, b) - - - def LeftDockable(self, b=True): - """ - Indicates whether a pane can be docked on the left of the frame. - - :param bool `b`: whether the pane can be docked at the left or not. - """ - - return self.SetFlag(self.optionLeftDockable, b) - - - def RightDockable(self, b=True): - """ - Indicates whether a pane can be docked on the right of the frame. - - :param bool `b`: whether the pane can be docked at the right or not. - """ - - return self.SetFlag(self.optionRightDockable, b) - - - def Floatable(self, b=True): - """ - Sets whether the user will be able to undock a pane and turn it - into a floating window. - - :param bool `b`: whether the pane can be floated or not. - """ - - return self.SetFlag(self.optionFloatable, b) - - - def Movable(self, b=True): - """ - Indicates whether a pane can be moved. - - :param bool `b`: whether the pane can be moved or not. - """ - - return self.SetFlag(self.optionMovable, b) - - - def NotebookDockable(self, b=True): - """ - Indicates whether a pane can be docked in an automatic :class:`~lib.agw.aui.auibook.AuiNotebook`. - - :param bool `b`: whether the pane can be docked in a notebook or not. - """ - - return self.SetFlag(self.optionNotebookDockable, b) - - - def DockFixed(self, b=True): - """ - Causes the containing dock to have no resize sash. This is useful - for creating panes that span the entire width or height of a dock, but should - not be resizable in the other direction. - - :param bool `b`: whether the pane will have a resize sash or not. - """ - - return self.SetFlag(self.optionDockFixed, b) - - - def Dockable(self, b=True): - """ - Specifies whether a frame can be docked or not. It is the same as specifying - :meth:`TopDockable` . :meth:`BottomDockable` . :meth:`LeftDockable` . :meth:`RightDockable` . - - :param bool `b`: whether the frame can be docked or not. - """ - - return self.TopDockable(b).BottomDockable(b).LeftDockable(b).RightDockable(b) - - - def TopSnappable(self, b=True): - """ - Indicates whether a pane can be snapped at the top of the main frame. - - :param bool `b`: whether the pane can be snapped at the top of the main frame or not. - """ - - return self.SetFlag(self.optionTopSnapped, b) - - - def BottomSnappable(self, b=True): - """ - Indicates whether a pane can be snapped at the bottom of the main frame. - - :param bool `b`: whether the pane can be snapped at the bottom of the main frame or not. - """ - - return self.SetFlag(self.optionBottomSnapped, b) - - - def LeftSnappable(self, b=True): - """ - Indicates whether a pane can be snapped on the left of the main frame. - - :param bool `b`: whether the pane can be snapped at the left of the main frame or not. - """ - - return self.SetFlag(self.optionLeftSnapped, b) - - - def RightSnappable(self, b=True): - """ - Indicates whether a pane can be snapped on the right of the main frame. - - :param bool `b`: whether the pane can be snapped at the right of the main frame or not. - """ - - return self.SetFlag(self.optionRightSnapped, b) - - - def Snappable(self, b=True): - """ - Indicates whether a pane can be snapped on the main frame. This is - equivalent as calling :meth:`TopSnappable` . :meth:`BottomSnappable` . :meth:`LeftSnappable` . :meth:`RightSnappable` . - - :param bool `b`: whether the pane can be snapped on the main frame or not. - """ - - return self.TopSnappable(b).BottomSnappable(b).LeftSnappable(b).RightSnappable(b) - - - def FlyOut(self, b=True): - """ - Indicates whether a pane, when floating, has a "fly-out" effect - (i.e., floating panes which only show themselves when moused over). - - :param bool `b`: whether the pane can be snapped on the main frame or not. - """ - - return self.SetFlag(self.optionFlyOut, b) - - - # Copy over the members that pertain to docking position - def SetDockPos(self, source): - """ - Copies the `source` pane members that pertain to docking position to `self`. - - :param AuiPaneInfo `source`: the source pane from where to copy the attributes. - """ - - self.dock_direction = source.dock_direction - self.dock_layer = source.dock_layer - self.dock_row = source.dock_row - self.dock_pos = source.dock_pos - self.dock_proportion = source.dock_proportion - self.floating_pos = wx.Point(*source.floating_pos) - self.floating_size = wx.Size(*source.floating_size) - self.rect = wx.Rect(*source.rect) - - return self - - - def DefaultPane(self): - """ Specifies that the pane should adopt the default pane settings. """ - - state = self.state - state |= self.optionTopDockable | self.optionBottomDockable | \ - self.optionLeftDockable | self.optionRightDockable | \ - self.optionNotebookDockable | \ - self.optionFloatable | self.optionMovable | self.optionResizable | \ - self.optionCaption | self.optionPaneBorder | self.buttonClose - - self.state = state - return self - - - def CentrePane(self): - """ - Specifies that the pane should adopt the default center pane settings. - - Centre panes usually do not have caption bars. This function provides an easy way of - preparing a pane to be displayed in the center dock position. - """ - - return self.CenterPane() - - - def CenterPane(self): - """ - Specifies that the pane should adopt the default center pane settings. - - Centre panes usually do not have caption bars. This function provides an easy way of - preparing a pane to be displayed in the center dock position. - """ - - self.state = 0 - return self.Center().PaneBorder().Resizable() - - - def ToolbarPane(self): - """ Specifies that the pane should adopt the default toolbar pane settings. """ - - self.DefaultPane() - state = self.state - - state |= (self.optionToolbar | self.optionGripper) - state &= ~(self.optionResizable | self.optionCaption | self.optionCaptionLeft | self.buttonClose) - - if self.dock_layer == 0: - self.dock_layer = 10 - - self.state = state - - return self - - - def Icon(self, icon): - """ - Specifies whether an icon is drawn on the left of the caption text when - the pane is docked. If `icon` is ``None`` or :class:`NullIcon`, no icon is drawn on - the caption space. - - :param icon: an icon to draw on the caption space, or ``None``. - :type `icon`: :class:`Icon` or ``None`` - """ - - if icon is None: - icon = wx.NullIcon - - self.icon = icon - return self - - - def SetFlag(self, flag, option_state): - """ - Turns the property given by `flag` on or off with the `option_state` - parameter. - - :param integer `flag`: the property to set; - :param bool `option_state`: either ``True`` or ``False``. - """ - - state = self.state - - if option_state: - state |= flag - else: - state &= ~flag - - self.state = state - - if flag in [self.buttonClose, self.buttonMaximize, self.buttonMinimize, self.buttonPin]: - self.ResetButtons() - - return self - - - def HasFlag(self, flag): - """ - Returns ``True`` if the the property specified by flag is active for the pane. - - :param integer `flag`: the property to check for activity. - """ - - return (self.state & flag and [True] or [False])[0] - - - def ResetButtons(self): - """ - Resets all the buttons and recreates them from scratch depending on the - :class:`AuiManager` flags. - """ - - floating = self.HasFlag(self.optionFloating) - self.buttons = [] - - if not floating and self.HasMinimizeButton(): - button = AuiPaneButton(AUI_BUTTON_MINIMIZE) - self.buttons.append(button) - - if not floating and self.HasMaximizeButton(): - button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE) - self.buttons.append(button) - - if not floating and self.HasPinButton(): - button = AuiPaneButton(AUI_BUTTON_PIN) - self.buttons.append(button) - - if self.HasCloseButton(): - button = AuiPaneButton(AUI_BUTTON_CLOSE) - self.buttons.append(button) - - - def CountButtons(self): - """ Returns the number of visible buttons in the docked pane. """ - - n = 0 - - if self.HasCaption() or self.HasCaptionLeft(): - if isinstance(wx.GetTopLevelParent(self.window), AuiFloatingFrame): - return 1 - - if self.HasCloseButton(): - n += 1 - if self.HasMaximizeButton(): - n += 1 - if self.HasMinimizeButton(): - n += 1 - if self.HasPinButton(): - n += 1 - - return n - - - def IsHorizontal(self): - """ Returns ``True`` if the pane `dock_direction` is horizontal. """ - - return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM] - - def IsVertical(self): - """ Returns ``True`` if the pane `dock_direction` is vertical. """ - - return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT] - - -# Null AuiPaneInfo reference -NonePaneInfo = AuiPaneInfo() -""" Null :class:`AuiPaneInfo` reference, an invalid instance of :class:`AuiPaneInfo`. """ - - -# ---------------------------------------------------------------------------- # - -class AuiDockingGuide(wx.Frame): - """ Base class for :class:`AuiSingleDockingGuide` and :class:`AuiCenterDockingGuide`.""" - - def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, - size=wx.DefaultSize, style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP | - wx.FRAME_NO_TASKBAR | wx.NO_BORDER, name="AuiDockingGuide"): - """ - Default class constructor. Used internally, do not call it in your code! - - :param `parent`: the :class:`AuiManager` parent; - :param integer `id`: the window identifier. It may take a value of -1 to indicate a default value. - :param string `title`: the caption to be displayed on the frame's title bar. - :param Point `pos`: the window position. A value of (-1, -1) indicates a default position, - chosen by either the windowing system or wxPython, depending on platform. - :param Size `size`: the window size. A value of (-1, -1) indicates a default size, chosen by - either the windowing system or wxPython, depending on platform. - :param integer `style`: the window style. - :param string `name`: the name of the window. This parameter is used to associate a name with the - item, allowing the application user to set Motif resource values for individual windows. - """ - - wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name) - - - def HitTest(self, x, y): - """ - To be overridden by parent classes. - - :param integer `x`: the `x` mouse position; - :param integer `y`: the `y` mouse position. - """ - - return 0 - - - def ValidateNotebookDocking(self, valid): - """ - To be overridden by parent classes. - - :param bool `valid`: whether a pane can be docked on top to another to form an automatic - :class:`~lib.agw.aui.auibook.AuiNotebook`. - """ - - return 0 - -# ============================================================================ -# implementation -# ============================================================================ - -# --------------------------------------------------------------------------- -# AuiDockingGuideWindow -# --------------------------------------------------------------------------- - -class AuiDockingGuideWindow(wx.Window): - """ Target class for :class:`AuiDockingGuide` and :class:`AuiCenterDockingGuide`. """ - - def __init__(self, parent, rect, direction=0, center=False, useAero=False): - """ - Default class constructor. Used internally, do not call it in your code! - - :param `parent`: the :class:`AuiManager` parent; - :param Rect `rect`: the window rect; - :param integer `direction`: one of ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, ``wx.RIGHT``, - ``wx.CENTER``; - :param bool `center`: whether the calling class is a :class:`AuiCenterDockingGuide`; - :param bool `useAero`: whether to use the new Aero-style bitmaps or Whidbey-style bitmaps - for the docking guide. - """ - - wx.Window.__init__(self, parent, -1, rect.GetPosition(), rect.GetSize(), wx.NO_BORDER) - - self._direction = direction - self._center = center - self._valid = True - self._useAero = useAero - - self._bmp_unfocus, self._bmp_focus = GetDockingImage(direction, useAero, center) - - self._currentImage = self._bmp_unfocus - self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) - - self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) - self.Bind(wx.EVT_PAINT, self.OnPaint) - - - def SetValid(self, valid): - """ - Sets the docking direction as valid or invalid. - - :param bool `valid`: whether the docking direction is allowed or not. - """ - - self._valid = valid - - - def IsValid(self): - """ Returns whether the docking direction is valid. """ - - return self._valid - - - def OnEraseBackground(self, event): - """ - Handles the ``wx.EVT_ERASE_BACKGROUND`` event for :class:`AuiDockingGuideWindow`. - - :param `event`: a :class:`EraseEvent` to be processed. - - :note: This is intentionally empty to reduce flickering while drawing. - """ - - pass - - - def DrawBackground(self, dc): - """ - Draws the docking guide background. - - :param `dc`: a :class:`DC` device context object. - """ - - rect = self.GetClientRect() - - dc.SetPen(wx.TRANSPARENT_PEN) - dc.SetBrush(wx.Brush(colourTargetBackground)) - dc.DrawRectangleRect(rect) - - dc.SetPen(wx.Pen(colourTargetBorder)) - - left = rect.GetLeft() - top = rect.GetTop() - right = rect.GetRight() - bottom = rect.GetBottom() - - if self._direction != wx.CENTER: - - if not self._center or self._direction != wx.BOTTOM: - dc.DrawLine(left, top, right+1, top) - if not self._center or self._direction != wx.RIGHT: - dc.DrawLine(left, top, left, bottom+1) - if not self._center or self._direction != wx.LEFT: - dc.DrawLine(right, top, right, bottom+1) - if not self._center or self._direction != wx.TOP: - dc.DrawLine(left, bottom, right+1, bottom) - - dc.SetPen(wx.Pen(colourTargetShade)) - - if self._direction != wx.RIGHT: - dc.DrawLine(left + 1, top + 1, left + 1, bottom) - if self._direction != wx.BOTTOM: - dc.DrawLine(left + 1, top + 1, right, top + 1) - - - def DrawDottedLine(self, dc, point, length, vertical): - """ - Draws a dotted line (not used if the docking guide images are ok). - - :param `dc`: a :class:`DC` device context object; - :param `point`: a :class:`Point` where to start drawing the dotted line; - :param integer `length`: the length of the dotted line; - :param bool `vertical`: whether it is a vertical docking guide window or not. - """ - - for i in xrange(0, length, 2): - dc.DrawPoint(point.x, point.y) - if vertical: - point.y += 2 - else: - point.x += 2 - - - def DrawIcon(self, dc): - """ - Draws the docking guide icon (not used if the docking guide images are ok). - - :param `dc`: a :class:`DC` device context object. - """ - - rect = wx.Rect(*self.GetClientRect()) - point = wx.Point() - length = 0 - - rect.Deflate(4, 4) - dc.SetPen(wx.Pen(colourIconBorder)) - dc.SetBrush(wx.Brush(colourIconBackground)) - dc.DrawRectangleRect(rect) - - right1 = rect.GetRight() + 1 - bottom1 = rect.GetBottom() + 1 - - dc.SetPen(wx.Pen(colourIconShadow)) - dc.DrawLine(rect.x + 1, bottom1, right1 + 1, bottom1) - dc.DrawLine(right1, rect.y + 1, right1, bottom1 + 1) - - rect.Deflate(1, 1) - - if self._direction == wx.TOP: - rect.height -= rect.height / 2 - point = rect.GetBottomLeft() - length = rect.width - - elif self._direction == wx.LEFT: - rect.width -= rect.width / 2 - point = rect.GetTopRight() - length = rect.height - - elif self._direction == wx.RIGHT: - rect.x += rect.width / 2 - rect.width -= rect.width / 2 - point = rect.GetTopLeft() - length = rect.height - - elif self._direction == wx.BOTTOM: - rect.y += rect.height / 2 - rect.height -= rect.height / 2 - point = rect.GetTopLeft() - length = rect.width - - elif self._direction == wx.CENTER: - rect.Deflate(1, 1) - point = rect.GetTopLeft() - length = rect.width - - dc.GradientFillLinear(rect, colourIconDockingPart1, - colourIconDockingPart2, self._direction) - - dc.SetPen(wx.Pen(colourIconBorder)) - - if self._direction == wx.CENTER: - self.DrawDottedLine(dc, rect.GetTopLeft(), rect.width, False) - self.DrawDottedLine(dc, rect.GetTopLeft(), rect.height, True) - self.DrawDottedLine(dc, rect.GetBottomLeft(), rect.width, False) - self.DrawDottedLine(dc, rect.GetTopRight(), rect.height, True) - - elif self._direction in [wx.TOP, wx.BOTTOM]: - self.DrawDottedLine(dc, point, length, False) - - else: - self.DrawDottedLine(dc, point, length, True) - - - def DrawArrow(self, dc): - """ - Draws the docking guide arrow icon (not used if the docking guide images are ok). - - :param `dc`: a :class:`DC` device context object. - """ - - rect = self.GetClientRect() - point = wx.Point() - - point.x = (rect.GetLeft() + rect.GetRight()) / 2 - point.y = (rect.GetTop() + rect.GetBottom()) / 2 - rx, ry = wx.Size(), wx.Size() - - if self._direction == wx.TOP: - rx = wx.Size(1, 0) - ry = wx.Size(0, 1) - - elif self._direction == wx.LEFT: - rx = wx.Size(0, -1) - ry = wx.Size(1, 0) - - elif self._direction == wx.RIGHT: - rx = wx.Size(0, 1) - ry = wx.Size(-1, 0) - - elif self._direction == wx.BOTTOM: - rx = wx.Size(-1, 0) - ry = wx.Size(0, -1) - - point.x += ry.x*3 - point.y += ry.y*3 - - dc.SetPen(wx.Pen(colourIconArrow)) - - for i in xrange(4): - pt1 = wx.Point(point.x - rx.x*i, point.y - rx.y*i) - pt2 = wx.Point(point.x + rx.x*(i+1), point.y + rx.y*(i+1)) - dc.DrawLinePoint(pt1, pt2) - point.x += ry.x - point.y += ry.y - - - def OnPaint(self, event): - """ - Handles the ``wx.EVT_PAINT`` event for :class:`AuiDockingGuideWindow`. - - :param `event`: a :class:`PaintEvent` to be processed. - """ - - dc = wx.AutoBufferedPaintDC(self) - if self._currentImage.IsOk() and self._valid: - dc.DrawBitmap(self._currentImage, 0, 0, True) - else: - self.Draw(dc) - - - def Draw(self, dc): - """ - Draws the whole docking guide window (not used if the docking guide images are ok). - - :param `dc`: a :class:`DC` device context object. - """ - - self.DrawBackground(dc) - - if self._valid: - self.DrawIcon(dc) - self.DrawArrow(dc) - - - def UpdateDockGuide(self, pos): - """ - Updates the docking guide images depending on the mouse position, using focused - images if the mouse is inside the docking guide or unfocused images if it is - outside. - - :param `pos`: a :class:`Point` mouse position. - """ - - inside = self.GetScreenRect().Contains(pos) - - if inside: - image = self._bmp_focus - else: - image = self._bmp_unfocus - - if image != self._currentImage: - self._currentImage = image - self.Refresh() - self.Update() - - -# --------------------------------------------------------------------------- -# AuiSingleDockingGuide -# --------------------------------------------------------------------------- - -class AuiSingleDockingGuide(AuiDockingGuide): - """ A docking guide window for single docking hint (not diamond-shaped HUD). """ - - def __init__(self, parent, direction=0): - """ - Default class constructor. Used internally, do not call it in your code! - - :param `parent`: the :class:`AuiManager` parent; - :param integer `direction`: one of ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, ``wx.RIGHT``. - """ - - self._direction = direction - - style = wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP | \ - wx.FRAME_NO_TASKBAR | wx.NO_BORDER - - # Use of FRAME_SHAPED on wxMac causes the frame to be visible - # breaking the docking hints. - if wx.Platform != '__WXMAC__': - style |= wx.FRAME_SHAPED - - AuiDockingGuide.__init__(self, parent, style=style, name="auiSingleDockTarget") - - self.Hide() - - useAero = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES - useWhidbey = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES - - self._useAero = useAero or useWhidbey - self._valid = True - - if useAero: - sizeX, sizeY = aeroguideSizeX, aeroguideSizeY - elif useWhidbey: - sizeX, sizeY = whidbeySizeX, whidbeySizeY - else: - sizeX, sizeY = guideSizeX, guideSizeY - - if direction not in [wx.TOP, wx.BOTTOM]: - sizeX, sizeY = sizeY, sizeX - - if self._useAero: - self.CreateShapesWithStyle(useWhidbey) - - if wx.Platform == "__WXGTK__": - self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape) - else: - self.SetGuideShape() - - self.SetSize(self.region.GetBox().GetSize()) - else: - self.SetSize((sizeX, sizeY)) - - self.rect = wx.Rect(0, 0, sizeX, sizeY) - - if self._useAero: - useAero = (useWhidbey and [2] or [1])[0] - else: - useAero = 0 - - self.target = AuiDockingGuideWindow(self, self.rect, direction, False, useAero) - - - def CreateShapesWithStyle(self, useWhidbey): - """ - Creates the docking guide window shape based on which docking bitmaps are used. - - :param bool `useWhidbey`: if ``True``, use Whidbey-style bitmaps; if ``False``, use the - Aero-style bitmaps. - """ - - sizeX, sizeY = aeroguideSizeX, aeroguideSizeY - if useWhidbey: - sizeX, sizeY = whidbeySizeX, whidbeySizeY - - if self._direction not in [wx.TOP, wx.BOTTOM]: - sizeX, sizeY = sizeY, sizeX - - useAero = (useWhidbey and [2] or [1])[0] - bmp, dummy = GetDockingImage(self._direction, useAero, False) - region = wx.RegionFromBitmap(bmp) - - self.region = region - - - def AeroMove(self, pos): - """ - Moves the docking window to the new position. Overridden in children classes. - - :param Point `pos`: the new docking guide position. - """ - - pass - - - def SetGuideShape(self, event=None): - """ - Sets the correct shape for the docking guide window. - - :param `event`: on wxGTK, a :class:`WindowCreateEvent` event to process. - """ - - self.SetShape(self.region) - - if event is not None: - # Skip the event on wxGTK - event.Skip() - wx.CallAfter(wx.SafeYield, self, True) - - - def SetShape(self, region): - """ - If the platform supports it, sets the shape of the window to that depicted by `region`. - The system will not display or respond to any mouse event for the pixels that lie - outside of the region. To reset the window to the normal rectangular shape simply call - :meth:`SetShape` again with an empty region. - - :param Region `region`: the shape of the frame. - - :note: Overridden for wxMAC. - """ - - if wx.Platform == '__WXMAC__': - # HACK so we don't crash when SetShape is called - return - else: - super(AuiSingleDockingGuide, self).SetShape(region) - - - def SetValid(self, valid): - """ - Sets the docking direction as valid or invalid. - - :param bool `valid`: whether the docking direction is allowed or not. - """ - - self._valid = valid - - - def IsValid(self): - """ Returns whether the docking direction is valid. """ - - return self._valid - - - def UpdateDockGuide(self, pos): - """ - Updates the docking guide images depending on the mouse position, using focused - images if the mouse is inside the docking guide or unfocused images if it is - outside. - - :param Point `pos`: the mouse position. - """ - - self.target.UpdateDockGuide(pos) - - - def HitTest(self, x, y): - """ - Checks if the mouse position is inside the target window rect. - - :param integer `x`: the `x` mouse position; - :param integer `y`: the `y` mouse position. - """ - - if self.target.GetScreenRect().Contains((x, y)): - return wx.ALL - - return -1 - - -# --------------------------------------------------------------------------- -# AuiCenterDockingGuide -# --------------------------------------------------------------------------- - -class AuiCenterDockingGuide(AuiDockingGuide): - """ A docking guide window for multiple docking hint (diamond-shaped HUD). """ - - def __init__(self, parent): - """ - Default class constructor. - Used internally, do not call it in your code! - - :param `parent`: the :class:`AuiManager` parent. - """ - - AuiDockingGuide.__init__(self, parent, style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP | - wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.FRAME_SHAPED, - name="auiCenterDockTarget") - - self.Hide() - - self.CreateShapesWithStyle() - self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) - - if wx.Platform == "__WXGTK__": - self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape) - else: - self.SetGuideShape() - - self.SetSize(self.region.GetBox().GetSize()) - - self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) - self.Bind(wx.EVT_PAINT, self.OnPaint) - - - def CreateShapesWithStyle(self): - """ Creates the docking guide window shape based on which docking bitmaps are used. """ - - useAero = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES) != 0 - useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0 - - self._useAero = 0 - if useAero: - self._useAero = 1 - elif useWhidbey: - self._useAero = 2 - - if useAero: - sizeX, sizeY = aeroguideSizeX, aeroguideSizeY - elif useWhidbey: - sizeX, sizeY = whidbeySizeX, whidbeySizeY - else: - sizeX, sizeY = guideSizeX, guideSizeY - - rectLeft = wx.Rect(0, sizeY, sizeY, sizeX) - rectTop = wx.Rect(sizeY, 0, sizeX, sizeY) - rectRight = wx.Rect(sizeY+sizeX, sizeY, sizeY, sizeX) - rectBottom = wx.Rect(sizeY, sizeX + sizeY, sizeX, sizeY) - rectCenter = wx.Rect(sizeY, sizeY, sizeX, sizeX) - - if not self._useAero: - - self.targetLeft = AuiDockingGuideWindow(self, rectLeft, wx.LEFT, True, useAero) - self.targetTop = AuiDockingGuideWindow(self, rectTop, wx.TOP, True, useAero) - self.targetRight = AuiDockingGuideWindow(self, rectRight, wx.RIGHT, True, useAero) - self.targetBottom = AuiDockingGuideWindow(self, rectBottom, wx.BOTTOM, True, useAero) - self.targetCenter = AuiDockingGuideWindow(self, rectCenter, wx.CENTER, True, useAero) - - - # top-left diamond - tld = [wx.Point(rectTop.x, rectTop.y+rectTop.height-8), - wx.Point(rectLeft.x+rectLeft.width-8, rectLeft.y), - rectTop.GetBottomLeft()] - # bottom-left diamond - bld = [wx.Point(rectLeft.x+rectLeft.width-8, rectLeft.y+rectLeft.height), - wx.Point(rectBottom.x, rectBottom.y+8), - rectBottom.GetTopLeft()] - # top-right diamond - trd = [wx.Point(rectTop.x+rectTop.width, rectTop.y+rectTop.height-8), - wx.Point(rectRight.x+8, rectRight.y), - rectRight.GetTopLeft()] - # bottom-right diamond - brd = [wx.Point(rectRight.x+8, rectRight.y+rectRight.height), - wx.Point(rectBottom.x+rectBottom.width, rectBottom.y+8), - rectBottom.GetTopRight()] - - self._triangles = [tld[0:2], bld[0:2], - [wx.Point(rectTop.x+rectTop.width-1, rectTop.y+rectTop.height-8), - wx.Point(rectRight.x+7, rectRight.y)], - [wx.Point(rectRight.x+7, rectRight.y+rectRight.height), - wx.Point(rectBottom.x+rectBottom.width-1, rectBottom.y+8)]] - - region = wx.Region() - region.UnionRect(rectLeft) - region.UnionRect(rectTop) - region.UnionRect(rectRight) - region.UnionRect(rectBottom) - region.UnionRect(rectCenter) - region.UnionRegion(wx.RegionFromPoints(tld)) - region.UnionRegion(wx.RegionFromPoints(bld)) - region.UnionRegion(wx.RegionFromPoints(trd)) - region.UnionRegion(wx.RegionFromPoints(brd)) - - elif useAero: - - self._aeroBmp = aero_dock_pane.GetBitmap() - region = wx.RegionFromBitmap(self._aeroBmp) - - self._allAeroBmps = [aero_dock_pane_left.GetBitmap(), aero_dock_pane_top.GetBitmap(), - aero_dock_pane_right.GetBitmap(), aero_dock_pane_bottom.GetBitmap(), - aero_dock_pane_center.GetBitmap(), aero_dock_pane.GetBitmap()] - self._deniedBitmap = aero_denied.GetBitmap() - self._aeroRects = [rectLeft, rectTop, rectRight, rectBottom, rectCenter] - self._valid = True - - elif useWhidbey: - - self._aeroBmp = whidbey_dock_pane.GetBitmap() - region = wx.RegionFromBitmap(self._aeroBmp) - - self._allAeroBmps = [whidbey_dock_pane_left.GetBitmap(), whidbey_dock_pane_top.GetBitmap(), - whidbey_dock_pane_right.GetBitmap(), whidbey_dock_pane_bottom.GetBitmap(), - whidbey_dock_pane_center.GetBitmap(), whidbey_dock_pane.GetBitmap()] - self._deniedBitmap = whidbey_denied.GetBitmap() - self._aeroRects = [rectLeft, rectTop, rectRight, rectBottom, rectCenter] - self._valid = True - - - self.region = region - - - def SetGuideShape(self, event=None): - """ - Sets the correct shape for the docking guide window. - - :param `event`: on wxGTK, a :class:`WindowCreateEvent` event to process. - """ - - self.SetShape(self.region) - - if event is not None: - # Skip the event on wxGTK - event.Skip() - wx.CallAfter(wx.SafeYield, self, True) - - - def UpdateDockGuide(self, pos): - """ - Updates the docking guides images depending on the mouse position, using focused - images if the mouse is inside the docking guide or unfocused images if it is - outside. - - :param Point `pos`: the mouse position. - """ - - if not self._useAero: - for target in self.GetChildren(): - target.UpdateDockGuide(pos) - else: - lenRects = len(self._aeroRects) - for indx, rect in enumerate(self._aeroRects): - if rect.Contains(pos): - if self._allAeroBmps[indx] != self._aeroBmp: - if indx < lenRects - 1 or (indx == lenRects - 1 and self._valid): - self._aeroBmp = self._allAeroBmps[indx] - self.Refresh() - else: - self._aeroBmp = self._allAeroBmps[-1] - self.Refresh() - - return - - if self._aeroBmp != self._allAeroBmps[-1]: - self._aeroBmp = self._allAeroBmps[-1] - self.Refresh() - - - def HitTest(self, x, y): - """ - Checks if the mouse position is inside the target windows rect. - - :param integer `x`: the `x` mouse position; - :param integer `y`: the `y` mouse position. - """ - - if not self._useAero: - if self.targetLeft.GetScreenRect().Contains((x, y)): - return wx.LEFT - if self.targetTop.GetScreenRect().Contains((x, y)): - return wx.UP - if self.targetRight.GetScreenRect().Contains((x, y)): - return wx.RIGHT - if self.targetBottom.GetScreenRect().Contains((x, y)): - return wx.DOWN - if self.targetCenter.IsValid() and self.targetCenter.GetScreenRect().Contains((x, y)): - return wx.CENTER - else: - constants = [wx.LEFT, wx.UP, wx.RIGHT, wx.DOWN, wx.CENTER] - lenRects = len(self._aeroRects) - for indx, rect in enumerate(self._aeroRects): - if rect.Contains((x, y)): - if indx < lenRects or (indx == lenRects-1 and self._valid): - return constants[indx] - - return -1 - - - def ValidateNotebookDocking(self, valid): - """ - Sets whether a pane can be docked on top of another to create an automatic - :class:`~lib.agw.aui.auibook.AuiNotebook`. - - :param bool `valid`: whether a pane can be docked on top to another to form an automatic - :class:`~lib.agw.aui.auibook.AuiNotebook`. - """ - - if not self._useAero: - if self.targetCenter.IsValid() != valid: - self.targetCenter.SetValid(valid) - self.targetCenter.Refresh() - else: - if self._valid != valid: - self._valid = valid - self.Refresh() - - - def AeroMove(self, pos): - """ - Moves the docking guide window to the new position. - - :param Point `pos`: the new docking guide position. - """ - - if not self._useAero: - return - - useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0 - - if useWhidbey: - sizeX, sizeY = whidbeySizeX, whidbeySizeY - else: - sizeX, sizeY = aeroguideSizeX, aeroguideSizeY - - size = self.GetSize() - - leftRect, topRect, rightRect, bottomRect, centerRect = self._aeroRects - thePos = pos + wx.Point((size.x-sizeY)/2, (size.y-sizeX)/2) - - centerRect.SetPosition(thePos) - - leftRect.SetPosition(thePos + wx.Point(-sizeY, 0)) - topRect.SetPosition(thePos + wx.Point(0, -sizeY)) - rightRect.SetPosition(thePos + wx.Point(sizeX, 0)) - bottomRect.SetPosition(thePos + wx.Point(0, sizeX)) - - - def OnEraseBackground(self, event): - """ - Handles the ``wx.EVT_ERASE_BACKGROUND`` event for :class:`AuiCenterDockingGuide`. - - :param `event`: :class:`EraseEvent` to be processed. - - :note: This is intentionally empty to reduce flickering while drawing. - """ - - pass - - - def OnPaint(self, event): - """ - Handles the ``wx.EVT_PAINT`` event for :class:`AuiCenterDockingGuide`. - - :param `event`: a :class:`PaintEvent` to be processed. - """ - - dc = wx.AutoBufferedPaintDC(self) - - if self._useAero: - dc.SetBrush(wx.TRANSPARENT_BRUSH) - dc.SetPen(wx.TRANSPARENT_PEN) - else: - dc.SetBrush(wx.Brush(colourTargetBackground)) - dc.SetPen(wx.Pen(colourTargetBorder)) - - rect = self.GetClientRect() - dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) - - if self._useAero: - dc.DrawBitmap(self._aeroBmp, 0, 0, True) - if not self._valid: - diff = (self._useAero == 2 and [1] or [0])[0] - bmpX, bmpY = self._deniedBitmap.GetWidth(), self._deniedBitmap.GetHeight() - xPos, yPos = (rect.x + (rect.width)/2 - bmpX/2), (rect.y + (rect.height)/2 - bmpY/2) - dc.DrawBitmap(self._deniedBitmap, xPos+1, yPos+diff, True) - - return - - dc.SetPen(wx.Pen(colourTargetBorder, 2)) - for pts in self._triangles: - dc.DrawLinePoint(pts[0], pts[1]) - - -# ---------------------------------------------------------------------------- -# AuiDockingHintWindow -# ---------------------------------------------------------------------------- - -class AuiDockingHintWindow(wx.Frame): - """ The original wxAUI docking window hint. """ - - def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, - size=wx.Size(1, 1), style=wx.FRAME_TOOL_WINDOW | wx.FRAME_FLOAT_ON_PARENT | - wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.FRAME_SHAPED, - name="auiHintWindow"): - """ - Default class constructor. Used internally, do not call it in your code! - - :param `parent`: the :class:`AuiManager` parent; - :param integer `id`: the window identifier. It may take a value of -1 to indicate a default value. - :param string `title`: the caption to be displayed on the frame's title bar; - :param Point `pos`: the window position. A value of (-1, -1) indicates a default position, - chosen by either the windowing system or wxPython, depending on platform; - :param Size `size`: the window size. A value of (-1, -1) indicates a default size, chosen by - either the windowing system or wxPython, depending on platform; - :param integer `style`: the window style; - :param string `name`: the name of the window. This parameter is used to associate a name with the - item, allowing the application user to set Motif resource values for individual windows. - """ - if wx.Platform == '__WXMAC__' and style & wx.FRAME_SHAPED: - # Having the shaped frame causes the frame to not be visible - # with the transparent style hints. - style -= wx.FRAME_SHAPED - - wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name) - - self._blindMode = False - - self._art = parent.GetEventHandler().GetArtProvider() - background = self._art.GetColour(AUI_DOCKART_HINT_WINDOW_COLOUR) - self.SetBackgroundColour(background) - - # Can't set background colour on a frame on wxMac - # so add a panel to set the colour on. - if wx.Platform == '__WXMAC__': - sizer = wx.BoxSizer(wx.HORIZONTAL) - self.panel = wx.Panel(self) - sizer.Add(self.panel, 1, wx.EXPAND) - self.SetSizer(sizer) - self.panel.SetBackgroundColour(background) - else: - self.Bind(wx.EVT_PAINT, self.OnPaint) - - self.Bind(wx.EVT_SIZE, self.OnSize) - - - def MakeVenetianBlinds(self): - """ - Creates the "venetian blind" effect if :class:`AuiManager` has the ``AUI_MGR_VENETIAN_BLINDS_HINT`` - flag set. - """ - - amount = 128 - size = self.GetClientSize() - region = wx.Region(0, 0, size.x, 1) - - for y in xrange(size.y): - - # Reverse the order of the bottom 4 bits - j = (y & 8 and [1] or [0])[0] | (y & 4 and [2] or [0])[0] | \ - (y & 2 and [4] or [0])[0] | (y & 1 and [8] or [0])[0] - - if 16*j+8 < amount: - region.Union(0, y, size.x, 1) - - self.SetShape(region) - - - def SetBlindMode(self, agwFlags): - """ - Sets whether venetian blinds or transparent hints will be shown as docking hint. - This depends on the :class:`AuiManager` flags. - - :param integer `agwFlags`: the :class:`AuiManager` flags. - """ - - self._blindMode = (agwFlags & AUI_MGR_VENETIAN_BLINDS_HINT) != 0 - - if self._blindMode or not self.CanSetTransparent(): - self.MakeVenetianBlinds() - self.SetTransparent(255) - - else: - self.SetShape(wx.Region()) - if agwFlags & AUI_MGR_HINT_FADE == 0: - self.SetTransparent(80) - else: - self.SetTransparent(0) - - - def SetShape(self, region): - """ - If the platform supports it, sets the shape of the window to that depicted by `region`. - The system will not display or respond to any mouse event for the pixels that lie - outside of the region. To reset the window to the normal rectangular shape simply call - :meth:`SetShape` again with an empty region. - - :param Region `region`: the shape of the frame. - - :note: Overridden for wxMAC. - """ - - if wx.Platform == '__WXMAC__': - # HACK so we don't crash when SetShape is called - return - else: - super(AuiDockingHintWindow, self).SetShape(region) - - - def Show(self, show=True): - """ - Show the hint window. - - :param bool `show`: whether to show or hide the hint docking window. - """ - - background = self._art.GetColour(AUI_DOCKART_HINT_WINDOW_COLOUR) - - if wx.Platform == '__WXMAC__': - self.panel.SetBackgroundColour(background) - else: - self.SetBackgroundColour(background) - - super(AuiDockingHintWindow, self).Show(show) - self.Refresh() - - if wx.Platform == '__WXMAC__': - # Need to manually do layout since its a borderless frame. - self.Layout() - - - def OnSize(self, event): - """ - Handles the ``wx.EVT_SIZE`` event for :class:`AuiDockingHintWindow`. - - :param `event`: a :class:`SizeEvent` to be processed. - """ - - if self._blindMode or not self.CanSetTransparent(): - self.MakeVenetianBlinds() - - self.Refresh() - - - def OnPaint(self, event): - """ - Handles the ``wx.EVT_PAINT`` event for :class:`AuiDockingHintWindow`. - - :param `event`: an instance of :class:`PaintEvent` to be processed. - """ - - rect = wx.RectPS(wx.Point(0, 0), self.GetSize()) - - dc = wx.PaintDC(self) - event.Skip() - - dc.SetBrush(wx.TRANSPARENT_BRUSH) - dc.SetPen(wx.Pen(wx.Colour(60, 60, 60), 5)) - rect.Deflate(1, 1) - dc.DrawRectangleRect(rect) - - -# ---------------------------------------------------------------------------- # - -# -- AuiFloatingFrame class implementation -- - -class AuiFloatingFrame(wx.MiniFrame): - """ AuiFloatingFrame is the frame class that holds floating panes. """ - - def __init__(self, parent, owner_mgr, pane=None, id=wx.ID_ANY, title="", - style=wx.FRAME_TOOL_WINDOW | wx.FRAME_FLOAT_ON_PARENT | - wx.FRAME_NO_TASKBAR | wx.CLIP_CHILDREN): - """ - Default class constructor. Used internally, do not call it in your code! - - :param `parent`: the :class:`AuiManager` parent; - :param `owner_mgr`: the :class:`AuiManager` that manages the floating pane; - :param `pane`: the :class:`AuiPaneInfo` pane that is about to float; - :param integer `id`: the window identifier. It may take a value of -1 to indicate a default value. - :param string `title`: the caption to be displayed on the frame's title bar. - :param integer `style`: the window style. - """ - - if pane and pane.IsResizeable(): - style |= wx.RESIZE_BORDER - if pane: - self._is_toolbar = pane.IsToolbar() - - self._useNativeMiniframes = False - if AuiManager_UseNativeMiniframes(owner_mgr): - # On wxMac we always use native miniframes - self._useNativeMiniframes = True - # windows does not support min/max boxes nor toggling the state - # of the close button. The only way to toggle that button is to - # toggle the system menu style. But the close box flag needs to - # be set from the beginning. - if wx.Platform == '__WXMSW__': - style |= wx.CAPTION | wx.CLOSE_BOX - if pane.HasCloseButton(): - style |= wx.SYSTEM_MENU - else: - style |= wx.CAPTION | wx.SYSTEM_MENU - if pane.HasCloseButton(): - style |= wx.CLOSE_BOX - if pane.HasMaximizeButton(): - style |= wx.MAXIMIZE_BOX - if pane.HasMinimizeButton(): - style |= wx.MINIMIZE_BOX - - wx.MiniFrame.__init__(self, parent, id, title, pos=pane.floating_pos, - size=pane.floating_size, style=style, name="auiFloatingFrame") - - self._fly_timer = wx.Timer(self, wx.ID_ANY) - self._check_fly_timer = wx.Timer(self, wx.ID_ANY) - - self.Bind(wx.EVT_CLOSE, self.OnClose) - self.Bind(wx.EVT_SIZE, self.OnSize) - self.Bind(wx.EVT_ACTIVATE, self.OnActivate) - self.Bind(wx.EVT_TIMER, self.OnCheckFlyTimer, self._check_fly_timer) - self.Bind(wx.EVT_TIMER, self.OnFlyTimer, self._fly_timer) - self.Bind(EVT_AUI_FIND_MANAGER, self.OnFindManager) - - if self._useNativeMiniframes: - self.Bind(wx.EVT_MOVE, self.OnMoveEvent) - self.Bind(wx.EVT_MOVING, self.OnMoveEvent) - self.Bind(wx.EVT_IDLE, self.OnIdle) - self._useNativeMiniframes = True - self.SetExtraStyle(wx.WS_EX_PROCESS_IDLE) - else: - self.Bind(wx.EVT_MOVE, self.OnMove) - - self._fly = False - self._send_size = True - self._alpha_amount = 255 - - self._owner_mgr = owner_mgr - self._moving = False - self._lastDirection = None - self._transparent = 255 - - self._last_rect = wx.Rect() - self._last2_rect = wx.Rect() - self._last3_rect = wx.Rect() - - self._mgr = AuiManager() - self._mgr.SetManagedWindow(self) - self._mgr.SetArtProvider(owner_mgr.GetArtProvider()) - self._mgr.SetAGWFlags(owner_mgr.GetAGWFlags()) - - - def CopyAttributes(self, pane): - """ - Copies all the attributes of the input `pane` into another :class:`AuiPaneInfo`. - - :param `pane`: the source :class:`AuiPaneInfo` from where to copy attributes. - """ - - contained_pane = AuiPaneInfo() - - contained_pane.name = pane.name - contained_pane.caption = pane.caption - contained_pane.window = pane.window - contained_pane.frame = pane.frame - contained_pane.state = pane.state - contained_pane.dock_direction = pane.dock_direction - contained_pane.dock_layer = pane.dock_layer - contained_pane.dock_row = pane.dock_row - contained_pane.dock_pos = pane.dock_pos - contained_pane.best_size = wx.Size(*pane.best_size) - contained_pane.min_size = wx.Size(*pane.min_size) - contained_pane.max_size = wx.Size(*pane.max_size) - contained_pane.floating_pos = wx.Point(*pane.floating_pos) - contained_pane.floating_size = wx.Size(*pane.floating_size) - contained_pane.dock_proportion = pane.dock_proportion - contained_pane.buttons = pane.buttons - contained_pane.rect = wx.Rect(*pane.rect) - contained_pane.icon = pane.icon - contained_pane.notebook_id = pane.notebook_id - contained_pane.transparent = pane.transparent - contained_pane.snapped = pane.snapped - contained_pane.minimize_mode = pane.minimize_mode - contained_pane.minimize_target = pane.minimize_target - - return contained_pane - - - def SetPaneWindow(self, pane): - """ - Sets all the properties of a pane. - - :param `pane`: the :class:`AuiPaneInfo` to analyze. - """ - - self._is_toolbar = pane.IsToolbar() - self._pane_window = pane.window - - if isinstance(pane.window, auibar.AuiToolBar): - pane.window.SetAuiManager(self._mgr) - - self._pane_window.Reparent(self) - - contained_pane = self.CopyAttributes(pane) - - contained_pane.Dock().Center().Show(). \ - CaptionVisible(False). \ - PaneBorder(False). \ - Layer(0).Row(0).Position(0) - - if not contained_pane.HasGripper() and not self._useNativeMiniframes: - contained_pane.CaptionVisible(True) - - indx = self._owner_mgr._panes.index(pane) - - # Carry over the minimum size - pane_min_size = pane.window.GetMinSize() - - # if the best size is smaller than the min size - # then set the min size to the best size as well - pane_best_size = contained_pane.best_size - if pane_best_size.IsFullySpecified() and (pane_best_size.x < pane_min_size.x or \ - pane_best_size.y < pane_min_size.y): - - pane_min_size = pane_best_size - self._pane_window.SetMinSize(pane_min_size) - - # if the frame window's max size is greater than the min size - # then set the max size to the min size as well - cur_max_size = self.GetMaxSize() - if cur_max_size.IsFullySpecified() and (cur_max_size.x < pane_min_size.x or \ - cur_max_size.y < pane_min_size.y): - self.SetMaxSize(pane_min_size) - - art_provider = self._mgr.GetArtProvider() - caption_size = art_provider.GetMetric(AUI_DOCKART_CAPTION_SIZE) - button_size = art_provider.GetMetric(AUI_DOCKART_PANE_BUTTON_SIZE) + \ - 4*art_provider.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE) - - min_size = pane.window.GetMinSize() - - if min_size.y < caption_size or min_size.x < button_size: - new_x, new_y = min_size.x, min_size.y - if min_size.y < caption_size: - new_y = (pane.IsResizeable() and [2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)+caption_size] or [1])[0] - if min_size.x < button_size: - new_x = (pane.IsResizeable() and [2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_X)+button_size] or [1])[0] - - self.SetMinSize((new_x, new_y)) - else: - self.SetMinSize(min_size) - - self._mgr.AddPane(self._pane_window, contained_pane) - self._mgr.Update() - - if pane.min_size.IsFullySpecified(): - # because SetSizeHints() calls Fit() too (which sets the window - # size to its minimum allowed), we keep the size before calling - # SetSizeHints() and reset it afterwards... - tmp = self.GetSize() - self.GetSizer().SetSizeHints(self) - self.SetSize(tmp) - - self.SetTitle(pane.caption) - - if pane.floating_size != wx.Size(-1, -1): - self.SetSize(pane.floating_size) - else: - size = pane.best_size - if size == wx.Size(-1, -1): - size = pane.min_size - if size == wx.Size(-1, -1): - size = self._pane_window.GetSize() - if self._owner_mgr and pane.HasGripper(): - if pane.HasGripperTop(): - size.y += self._owner_mgr._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE) - else: - size.x += self._owner_mgr._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE) - - if not self._useNativeMiniframes: - size.y += self._owner_mgr._art.GetMetric(AUI_DOCKART_CAPTION_SIZE) - - pane.floating_size = size - - self.SetClientSize(size) - - self._owner_mgr._panes[indx] = pane - - self._fly_step = abs(pane.floating_size.y - \ - (caption_size + 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)))/10 - - self._floating_size = wx.Size(*self.GetSize()) - - if pane.IsFlyOut(): - self._check_fly_timer.Start(50) - - - def GetOwnerManager(self): - """ Returns the :class:`AuiManager` that manages the pane. """ - - return self._owner_mgr - - - def OnSize(self, event): - """ - Handles the ``wx.EVT_SIZE`` event for :class:`AuiFloatingFrame`. - - :param `event`: a :class:`SizeEvent` to be processed. - """ - - if self._owner_mgr and self._send_size: - self._owner_mgr.OnFloatingPaneResized(self._pane_window, event.GetSize()) - - - def OnClose(self, event): - """ - Handles the ``wx.EVT_CLOSE`` event for :class:`AuiFloatingFrame`. - - :param `event`: a :class:`CloseEvent` to be processed. - """ - - if self._owner_mgr: - self._owner_mgr.OnFloatingPaneClosed(self._pane_window, event) - - if not event.GetVeto(): - self._mgr.DetachPane(self._pane_window) - - if isinstance(self._pane_window, auibar.AuiToolBar): - self._pane_window.SetAuiManager(self._owner_mgr) - - # if we do not do this, then we can crash... - if self._owner_mgr and self._owner_mgr._action_window == self: - self._owner_mgr._action_window = None - - self._mgr.UnInit() - self.Destroy() - - - def OnActivate(self, event): - """ - Handles the ``wx.EVT_ACTIVATE`` event for :class:`AuiFloatingFrame`. - - :param `event`: a :class:`ActivateEvent` to be processed. - """ - - if self._owner_mgr and event.GetActive(): - self._owner_mgr.OnFloatingPaneActivated(self._pane_window) - - - def OnMove(self, event): - """ - Handles the ``wx.EVT_MOVE`` event for :class:`AuiFloatingFrame`. - - :param `event`: a :class:`MoveEvent` to be processed. - - .. note:: - - This event is not processed on wxMAC or if :class:`AuiManager` is not using the - ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style. - - """ - - if self._owner_mgr: - self._owner_mgr.OnFloatingPaneMoved(self._pane_window, event) - - - def OnMoveEvent(self, event): - """ - Handles the ``wx.EVT_MOVE`` and ``wx.EVT_MOVING`` events for :class:`AuiFloatingFrame`. - - :param `event`: a :class:`MoveEvent` to be processed. - - .. note:: - - This event is only processed on wxMAC or if :class:`AuiManager` is using the - ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style. - """ - - win_rect = self.GetRect() - - if win_rect == self._last_rect: - return - - # skip the first move event - if self._last_rect.IsEmpty(): - self._last_rect = wx.Rect(*win_rect) - return - - # As on OSX moving windows are not getting all move events, only sporadically, this difference - # is almost always big on OSX, so avoid this early exit opportunity - if wx.Platform != '__WXMAC__': - # skip if moving too fast to avoid massive redraws and - # jumping hint windows - if abs(win_rect.x - self._last_rect.x) > 3 or abs(win_rect.y - self._last_rect.y) > 3: - self._last3_rect = wx.Rect(*self._last2_rect) - self._last2_rect = wx.Rect(*self._last_rect) - self._last_rect = wx.Rect(*win_rect) - - # However still update the internally stored position to avoid - # snapping back to the old one later. - if self._owner_mgr: - self._owner_mgr.GetPane(self._pane_window).floating_pos = win_rect.GetPosition() - - return - - # prevent frame redocking during resize - if self._last_rect.GetSize() != win_rect.GetSize(): - self._last3_rect = wx.Rect(*self._last2_rect) - self._last2_rect = wx.Rect(*self._last_rect) - self._last_rect = wx.Rect(*win_rect) - return - - dir = wx.ALL - - horiz_dist = abs(win_rect.x - self._last3_rect.x) - vert_dist = abs(win_rect.y - self._last3_rect.y) - - if vert_dist >= horiz_dist: - if win_rect.y < self._last3_rect.y: - dir = wx.NORTH - else: - dir = wx.SOUTH - else: - if win_rect.x < self._last3_rect.x: - dir = wx.WEST - else: - dir = wx.EAST - - self._last3_rect = wx.Rect(*self._last2_rect) - self._last2_rect = wx.Rect(*self._last_rect) - self._last_rect = wx.Rect(*win_rect) - - if _VERSION_STRING < "2.9": - leftDown = wx.GetMouseState().LeftDown() - else: - leftDown = wx.GetMouseState().LeftIsDown() - - if not leftDown: - return - - if not self._moving: - self.OnMoveStart(event) - self._moving = True - - if self._last3_rect.IsEmpty(): - return - - if event.GetEventType() == wx.wxEVT_MOVING: - self.OnMoving(event.GetRect(), dir) - else: - self.OnMoving(wx.RectPS(event.GetPosition(), self.GetSize()), dir) - - - def OnIdle(self, event): - """ - Handles the ``wx.EVT_IDLE`` event for :class:`AuiFloatingFrame`. - - :param `event`: a :class:`IdleEvent` event to be processed. - - .. note:: - - This event is only processed on wxMAC if :class:`AuiManager` is using the - ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style. - - """ - - if self._moving: - if _VERSION_STRING < "2.9": - leftDown = wx.GetMouseState().LeftDown() - else: - leftDown = wx.GetMouseState().LeftIsDown() - - if not leftDown: - self._moving = False - self.OnMoveFinished() - else: - event.RequestMore() - - - def OnMoveStart(self, event): - """ - The user has just started moving the floating pane. - - :param `event`: an instance of :class:`MouseEvent`. - - .. note:: - - This event is only processed on wxMAC if :class:`AuiManager` is using the - ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style. - - """ - - # notify the owner manager that the pane has started to move - if self._owner_mgr: - if self._owner_mgr._from_move: - return - self._owner_mgr._action_window = self._pane_window - point = wx.GetMousePosition() - action_offset = point - self.GetPosition() - - if self._is_toolbar: - self._owner_mgr._toolbar_action_offset = action_offset - self._owner_mgr.OnMotion_DragToolbarPane(point) - else: - self._owner_mgr._action_offset = action_offset - self._owner_mgr.OnMotion_DragFloatingPane(point) - - - def OnMoving(self, rect, direction): - """ - The user is moving the floating pane. - - :param Rect `rect`: the pane client rectangle; - :param integer `direction`: the direction in which the pane is moving, can be one of - ``wx.NORTH``, ``wx.SOUTH``, ``wx.EAST`` or ``wx.WEST``. - - .. note:: - - This event is only processed on wxMAC if :class:`AuiManager` is using the - ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style. - """ - - # notify the owner manager that the pane is moving - self.OnMoveStart(None) - self._lastDirection = direction - - - def OnMoveFinished(self): - """ - The user has just finished moving the floating pane. - - .. note:: - - This method is used only on wxMAC if :class:`AuiManager` is using the - ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style. - - """ - - # notify the owner manager that the pane has finished moving - if self._owner_mgr: - self._owner_mgr._action_window = self._pane_window - point = wx.GetMousePosition() - if self._is_toolbar: - self._owner_mgr.OnLeftUp_DragToolbarPane(point) - else: - self._owner_mgr.OnLeftUp_DragFloatingPane(point) - - self._owner_mgr.OnFloatingPaneMoved(self._pane_window, point) - - - def OnCheckFlyTimer(self, event): - """ - Handles the ``wx.EVT_TIMER`` event for :class:`AuiFloatingFrame`. - - :param `event`: a :class:`TimerEvent` to be processed. - - :note: This is used solely for "fly-out" panes. - """ - - if self._owner_mgr: - pane = self._mgr.GetPane(self._pane_window) - if pane.IsFlyOut(): - if self.IsShownOnScreen(): - self.FlyOut() - - - def OnFindManager(self, event): - """ - Handles the ``EVT_AUI_FIND_MANAGER`` event for :class:`AuiFloatingFrame`. - - :param `event`: a :class:`AuiManagerEvent` event to be processed. - """ - - event.SetManager(self._owner_mgr) - - - def FlyOut(self): - """ Starts the flying in and out of a floating pane. """ - - if self._fly_timer.IsRunning(): - return - - if _VERSION_STRING < "2.9": - leftDown = wx.GetMouseState().LeftDown() - else: - leftDown = wx.GetMouseState().LeftIsDown() - - if leftDown: - return - - rect = wx.Rect(*self.GetScreenRect()) - rect.Inflate(10, 10) - - if rect.Contains(wx.GetMousePosition()): - if not self._fly: - return - self._send_size = False - self._fly_timer.Start(5) - else: - if self._fly: - return - self._send_size = False - self._fly_timer.Start(5) - - - def OnFlyTimer(self, event): - """ - Handles the ``wx.EVT_TIMER`` event for :class:`AuiFloatingFrame`. - - :param `event`: a :class:`TimerEvent` to be processed. - """ - - current_size = self.GetClientSize() - floating_size = wx.Size(*self._owner_mgr.GetPane(self._pane_window).floating_size) - - if floating_size.y == -1: - floating_size = self._floating_size - - if not self._fly: - min_size = self._mgr.GetArtProvider().GetMetric(AUI_DOCKART_CAPTION_SIZE) - - if wx.Platform != "__WXMSW__": - min_size += 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y) - - if current_size.y - self._fly_step <= min_size: - self.SetClientSize((current_size.x, min_size)) - self._fly = True - self._fly_timer.Stop() - self._send_size = True - else: - self.SetClientSize((current_size.x, current_size.y-self._fly_step)) - - else: - if current_size.y + self._fly_step >= floating_size.y: - self.SetClientSize((current_size.x, floating_size.y)) - self._fly = False - self._fly_timer.Stop() - self._send_size = True - else: - self.SetClientSize((current_size.x, current_size.y+self._fly_step)) - - self.Update() - self.Refresh() - - - def FadeOut(self): - """ Actually starts the fading out of the floating pane. """ - - while 1: - self._alpha_amount -= 10 - if self._alpha_amount <= 0: - self._alpha_amount = 255 - return - - self.SetTransparent(self._alpha_amount) - wx.SafeYield() - wx.MilliSleep(15) - - -# -- static utility functions -- - -def DrawResizeHint(dc, rect): - """ - Draws a resize hint while a sash is dragged. - - :param Rect `rect`: a rectangle which specifies the sash dimensions. - """ - - if wx.Platform == "__WXMSW__" and wx.App.GetComCtl32Version() >= 600: - if wx.GetOsVersion()[1] > 5: - # Windows Vista - dc.SetPen(wx.Pen("black", 2, wx.SOLID)) - dc.SetBrush(wx.TRANSPARENT_BRUSH) - else: - # Draw the nice XP style splitter - dc.SetPen(wx.TRANSPARENT_PEN) - dc.SetBrush(wx.BLACK_BRUSH) - dc.SetLogicalFunction(wx.INVERT) - dc.DrawRectangleRect(rect) - dc.SetLogicalFunction(wx.COPY) - else: - stipple = PaneCreateStippleBitmap() - brush = wx.BrushFromBitmap(stipple) - dc.SetBrush(brush) - dc.SetPen(wx.TRANSPARENT_PEN) - - dc.SetLogicalFunction(wx.XOR) - dc.DrawRectangleRect(rect) - - -def CopyDocksAndPanes(src_docks, src_panes): - """ - This utility function creates shallow copies of - the dock and pane info. :class:`AuiManager` usually contain pointers - to :class:`AuiPaneInfo` classes, thus this function is necessary to reliably - reconstruct that relationship in the new dock info and pane info arrays. - - :param `src_docks`: a list of :class:`AuiDockInfo` classes; - :param `src_panes`: a list of :class:`AuiPaneInfo` classes. - """ - - dest_docks = src_docks - dest_panes = src_panes - - for ii in xrange(len(dest_docks)): - dock = dest_docks[ii] - for jj in xrange(len(dock.panes)): - for kk in xrange(len(src_panes)): - if dock.panes[jj] == src_panes[kk]: - dock.panes[jj] = dest_panes[kk] - - return dest_docks, dest_panes - - -def CopyDocksAndPanes2(src_docks, src_panes): - """ - This utility function creates full copies of - the dock and pane info. :class:`AuiManager` usually contain pointers - to :class:`AuiPaneInfo` classes, thus this function is necessary to reliably - reconstruct that relationship in the new dock info and pane info arrays. - - :param `src_docks`: a list of :class:`AuiDockInfo` classes; - :param `src_panes`: a list of :class:`AuiPaneInfo` classes. - """ - - dest_docks = [] - - for ii in xrange(len(src_docks)): - dest_docks.append(AuiDockInfo()) - dest_docks[ii].dock_direction = src_docks[ii].dock_direction - dest_docks[ii].dock_layer = src_docks[ii].dock_layer - dest_docks[ii].dock_row = src_docks[ii].dock_row - dest_docks[ii].size = src_docks[ii].size - dest_docks[ii].min_size = src_docks[ii].min_size - dest_docks[ii].resizable = src_docks[ii].resizable - dest_docks[ii].fixed = src_docks[ii].fixed - dest_docks[ii].toolbar = src_docks[ii].toolbar - dest_docks[ii].panes = src_docks[ii].panes - dest_docks[ii].rect = wx.Rect(*src_docks[ii].rect) - - dest_panes = [] - - for ii in xrange(len(src_panes)): - dest_panes.append(AuiPaneInfo()) - dest_panes[ii].name = src_panes[ii].name - dest_panes[ii].caption = src_panes[ii].caption - dest_panes[ii].window = src_panes[ii].window - dest_panes[ii].frame = src_panes[ii].frame - dest_panes[ii].state = src_panes[ii].state - dest_panes[ii].dock_direction = src_panes[ii].dock_direction - dest_panes[ii].dock_layer = src_panes[ii].dock_layer - dest_panes[ii].dock_row = src_panes[ii].dock_row - dest_panes[ii].dock_pos = src_panes[ii].dock_pos - dest_panes[ii].best_size = wx.Size(*src_panes[ii].best_size) - dest_panes[ii].min_size = wx.Size(*src_panes[ii].min_size) - dest_panes[ii].max_size = wx.Size(*src_panes[ii].max_size) - dest_panes[ii].floating_pos = wx.Point(*src_panes[ii].floating_pos) - dest_panes[ii].floating_size = wx.Size(*src_panes[ii].floating_size) - dest_panes[ii].dock_proportion = src_panes[ii].dock_proportion - dest_panes[ii].buttons = src_panes[ii].buttons - dest_panes[ii].rect = wx.Rect(*src_panes[ii].rect) - dest_panes[ii].icon = src_panes[ii].icon - dest_panes[ii].notebook_id = src_panes[ii].notebook_id - dest_panes[ii].transparent = src_panes[ii].transparent - dest_panes[ii].snapped = src_panes[ii].snapped - dest_panes[ii].minimize_mode = src_panes[ii].minimize_mode - dest_panes[ii].minimize_target = src_panes[ii].minimize_target - - for ii in xrange(len(dest_docks)): - dock = dest_docks[ii] - for jj in xrange(len(dock.panes)): - for kk in xrange(len(src_panes)): - if dock.panes[jj] == src_panes[kk]: - dock.panes[jj] = dest_panes[kk] - - dest_docks[ii] = dock - - return dest_docks, dest_panes - - -def GetMaxLayer(docks, dock_direction): - """ - This is an internal function which returns - the highest layer inside the specified dock. - - :param `docks`: a list of :class:`AuiDockInfo`; - :param `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze. - """ - - max_layer = 0 - - for dock in docks: - if dock.dock_direction == dock_direction and dock.dock_layer > max_layer and not dock.fixed: - max_layer = dock.dock_layer - - return max_layer - - -def GetMaxRow(panes, dock_direction, dock_layer): - """ - This is an internal function which returns - the highest layer inside the specified dock. - - :param `panes`: a list of :class:`AuiPaneInfo`; - :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze; - :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze. - """ - - max_row = 0 - - for pane in panes: - if pane.dock_direction == dock_direction and pane.dock_layer == dock_layer and \ - pane.dock_row > max_row: - max_row = pane.dock_row - - return max_row - - -def DoInsertDockLayer(panes, dock_direction, dock_layer): - """ - This is an internal function that inserts a new dock - layer by incrementing all existing dock layer values by one. - - :param `panes`: a list of :class:`AuiPaneInfo`; - :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze; - :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze. - """ - - for ii in xrange(len(panes)): - pane = panes[ii] - if not pane.IsFloating() and pane.dock_direction == dock_direction and pane.dock_layer >= dock_layer: - pane.dock_layer = pane.dock_layer + 1 - - panes[ii] = pane - - return panes - - -def DoInsertDockRow(panes, dock_direction, dock_layer, dock_row): - """ - This is an internal function that inserts a new dock - row by incrementing all existing dock row values by one. - - :param `panes`: a list of :class:`AuiPaneInfo`; - :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze; - :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze; - :param integer `dock_row`: the :class:`AuiDockInfo` row to analyze. - """ - - for pane in panes: - if not pane.IsFloating() and pane.dock_direction == dock_direction and \ - pane.dock_layer == dock_layer and pane.dock_row >= dock_row: - pane.dock_row += 1 - - return panes - - -def DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos): - """ - This is an internal function that inserts a new pane - by incrementing all existing dock position values by one. - - :param `panes`: a list of :class:`AuiPaneInfo`; - :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze; - :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze. - :param integer `dock_row`: the :class:`AuiDockInfo` row to analyze; - :param integer `dock_pos`: the :class:`AuiDockInfo` position to analyze. - """ - - for ii in xrange(len(panes)): - pane = panes[ii] - if not pane.IsFloating() and pane.dock_direction == dock_direction and \ - pane.dock_layer == dock_layer and pane.dock_row == dock_row and \ - pane.dock_pos >= dock_pos: - pane.dock_pos = pane.dock_pos + 1 - - panes[ii] = pane - - return panes - - -def FindDocks(docks, dock_direction, dock_layer=-1, dock_row=-1, reverse=False): - """ - This is an internal function that returns a list of docks which meet - the specified conditions in the parameters and returns a sorted array - (sorted by layer and then row). - - :param `docks`: a list of :class:`AuiDockInfo`; - :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze; - :param integer `dock_layer`: the :class:`AuiDockInfo` layer to analyze. - :param integer `dock_row`: the :class:`AuiDockInfo` row to analyze; - """ - - matchDocks = [(d.dock_layer, d.dock_row, d.dock_direction, d) for d in docks if \ - (dock_direction == -1 or dock_direction == d.dock_direction) and \ - ((dock_layer == -1 or dock_layer == d.dock_layer) and \ - (dock_row == -1 or dock_row == d.dock_row))] - - arr = [x[-1] for x in sorted(matchDocks, reverse=reverse)] - - return arr - - -def FindOppositeDocks(docks, dock_direction): - """ - This is an internal function that returns a list of docks - which is related to the opposite direction. - - :param `docks`: a list of :class:`AuiDockInfo`; - :param integer `dock_direction`: the :class:`AuiDockInfo` docking direction to analyze; - """ - - if dock_direction == AUI_DOCK_LEFT: - arr = FindDocks(docks, AUI_DOCK_RIGHT, -1, -1) - elif dock_direction == AUI_DOCK_TOP: - arr = FindDocks(docks, AUI_DOCK_BOTTOM, -1, -1) - elif dock_direction == AUI_DOCK_RIGHT: - arr = FindDocks(docks, AUI_DOCK_LEFT, -1, -1) - elif dock_direction == AUI_DOCK_BOTTOM: - arr = FindDocks(docks, AUI_DOCK_TOP, -1, -1) - - return arr - - -def FindPaneInDock(dock, window): - """ - This method looks up a specified window pointer inside a dock. - If found, the corresponding :class:`AuiDockInfo` pointer is returned, otherwise ``None``. - - :param `dock`: a :class:`AuiDockInfo` structure; - :param Window `window`: the window associated to the pane we are seeking. - """ - - for p in dock.panes: - if p.window == window: - return p - - return None - - -def GetToolBarDockOffsets(docks): - """ - Returns the toolbar dock offsets (top-left and bottom-right). - - :param `docks`: a list of :class:`AuiDockInfo` to analyze. - """ - - top_left = wx.Size(0, 0) - bottom_right = wx.Size(0, 0) - - for dock in docks: - if dock.toolbar: - dock_direction = dock.dock_direction - if dock_direction == AUI_DOCK_LEFT: - top_left.x += dock.rect.width - bottom_right.x += dock.rect.width - - elif dock_direction == AUI_DOCK_TOP: - top_left.y += dock.rect.height - bottom_right.y += dock.rect.height - - elif dock_direction == AUI_DOCK_RIGHT: - bottom_right.x += dock.rect.width - - elif dock_direction == AUI_DOCK_BOTTOM: - bottom_right.y += dock.rect.height - - return top_left, bottom_right - - -def GetInternalFrameRect(window, docks): - """ - Returns the window rectangle excluding toolbars. - - :param `window`: a :class:`Window` derived window; - :param `docks`: a list of :class:`AuiDockInfo` structures. - """ - - frameRect = wx.Rect() - - frameRect.SetTopLeft(window.ClientToScreen(window.GetClientAreaOrigin())) - frameRect.SetSize(window.GetClientSize()) - - top_left, bottom_right = GetToolBarDockOffsets(docks) - - # make adjustments for toolbars - frameRect.x += top_left.x - frameRect.y += top_left.y - frameRect.width -= bottom_right.x - frameRect.height -= bottom_right.y - - return frameRect - - -def CheckOutOfWindow(window, pt): - """ - Checks if a point is outside the window rectangle. - - :param `window`: a :class:`Window` derived window; - :param `pt`: a :class:`Point` object. - """ - - auiWindowMargin = 30 - marginRect = wx.Rect(*window.GetClientRect()) - marginRect.Inflate(auiWindowMargin, auiWindowMargin) - - return not marginRect.Contains(pt) - - -def CheckEdgeDrop(window, docks, pt): - """ - Checks on which edge of a window the drop action has taken place. - - :param `window`: a :class:`Window` derived window; - :param `docks`: a list of :class:`AuiDockInfo` structures; - :param `pt`: a :class:`Point` object. - """ - - screenPt = window.ClientToScreen(pt) - clientSize = window.GetClientSize() - frameRect = GetInternalFrameRect(window, docks) - - if screenPt.y >= frameRect.GetTop() and screenPt.y < frameRect.GetBottom(): - if pt.x < auiLayerInsertOffset and pt.x > auiLayerInsertOffset - auiLayerInsertPixels: - return wx.LEFT - - if pt.x >= clientSize.x - auiLayerInsertOffset and \ - pt.x < clientSize.x - auiLayerInsertOffset + auiLayerInsertPixels: - return wx.RIGHT - - if screenPt.x >= frameRect.GetLeft() and screenPt.x < frameRect.GetRight(): - if pt.y < auiLayerInsertOffset and pt.y > auiLayerInsertOffset - auiLayerInsertPixels: - return wx.TOP - - if pt.y >= clientSize.y - auiLayerInsertOffset and \ - pt.y < clientSize.y - auiLayerInsertOffset + auiLayerInsertPixels: - return wx.BOTTOM - - return -1 - - -def RemovePaneFromDocks(docks, pane, exc=None): - """ - Removes a pane window from all docks - with a possible exception specified by parameter `exc`. - - :param `docks`: a list of :class:`AuiDockInfo` structures; - :param AuiPaneInfo `pane`: the pane to be removed; - :param AuiPaneInfo `exc`: the possible pane exception. - """ - - for ii in xrange(len(docks)): - d = docks[ii] - if d == exc: - continue - pi = FindPaneInDock(d, pane.window) - if pi: - d.panes.remove(pi) - - docks[ii] = d - - return docks - - -def RenumberDockRows(docks): - """ - Takes a dock and assigns sequential numbers - to existing rows. Basically it takes out the gaps so if a - dock has rows with numbers 0, 2, 5, they will become 0, 1, 2. - - :param `docks`: a list of :class:`AuiDockInfo` structures. - """ - - for ii in xrange(len(docks)): - dock = docks[ii] - dock.dock_row = ii - for jj in xrange(len(dock.panes)): - dock.panes[jj].dock_row = ii - - docks[ii] = dock - - return docks - - -def SetActivePane(panes, active_pane): - """ - Sets the active pane, as well as cycles through - every other pane and makes sure that all others' active flags - are turned off. - - :param `panes`: a list of :class:`AuiPaneInfo` structures; - :param AuiPaneInfo `active_pane`: the pane to be made active (if found). - """ - - for pane in panes: - pane.state &= ~AuiPaneInfo.optionActive - - for pane in panes: - if pane.window == active_pane and not pane.IsNotebookPage(): - pane.state |= AuiPaneInfo.optionActive - return True, panes - - return False, panes - - -def ShowDockingGuides(guides, show): - """ - Shows or hide the docking guide windows. - - :param `guides`: a list of :class:`AuiDockingGuide` classes; - :param bool `show`: whether to show or hide the docking guide windows. - """ - - for target in guides: - - if show and not target.host.IsShown(): - target.host.Show() - target.host.Update() - - elif not show and target.host.IsShown(): - target.host.Hide() - - -def RefreshDockingGuides(guides): - """ - Refreshes the docking guide windows. - - :param `guides`: a list of :class:`AuiDockingGuide` classes; - """ - - for target in guides: - if target.host.IsShown(): - target.host.Refresh() - - -def PaneSortFunc(p1, p2): - """ - This function is used to sort panes by dock position. - - :param AuiPaneInfo `p1`: the first pane instance to compare; - :param AuiPaneInfo `p2`: the second pane instance to compare. - """ - - return (p1.dock_pos < p2.dock_pos and [-1] or [1])[0] - - -def GetNotebookRoot(panes, notebook_id): - """ - Returns the :class:`~lib.agw.aui.auibook.AuiNotebook` which has the specified `notebook_id`. - - :param `panes`: a list of :class:`AuiPaneInfo` instances; - :param integer `notebook_id`: the target notebook id. - """ - - for paneInfo in panes: - if paneInfo.IsNotebookControl() and paneInfo.notebook_id == notebook_id: - return paneInfo - - return None - - -def EscapeDelimiters(s): - """ - Changes ``;`` into ``\`` and ``|`` into ``\|`` in the input string. - - :param string `s`: the string to be analyzed. - - :note: This is an internal functions which is used for saving perspectives. - """ - - result = s.replace(";", "\\") - result = result.replace("|", "|\\") - - return result - - -def IsDifferentDockingPosition(pane1, pane2): - """ - Returns whether `pane1` and `pane2` are in a different docking position - based on pane status, docking direction, docking layer and docking row. - - :param `pane1`: a :class:`AuiPaneInfo` instance; - :param `pane2`: another :class:`AuiPaneInfo` instance. - """ - - return pane1.IsFloating() != pane2.IsFloating() or \ - pane1.dock_direction != pane2.dock_direction or \ - pane1.dock_layer != pane2.dock_layer or \ - pane1.dock_row != pane2.dock_row - - -# Convenience function -def AuiManager_HasLiveResize(manager): - """ - Static function which returns if the input `manager` should have "live resize" - behaviour. - - :param `manager`: an instance of :class:`AuiManager`. - - .. note:: - - This method always returns ``True`` on wxMAC as this platform doesn't have - the ability to use :class:`ScreenDC` to draw sashes. - - """ - - # With Core Graphics on Mac, it's not possible to show sash feedback, - # so we'll always use live update instead. - - if wx.Platform == "__WXMAC__": - return True - else: - return (manager.GetAGWFlags() & AUI_MGR_LIVE_RESIZE) == AUI_MGR_LIVE_RESIZE - - -# Convenience function -def AuiManager_UseNativeMiniframes(manager): - """ - Static function which returns if the input `manager` should use native :class:`MiniFrame` as - floating panes. - - :param `manager`: an instance of :class:`AuiManager`. - - .. note:: - - This method always returns ``True`` on wxMAC as this platform doesn't have - the ability to use custom drawn miniframes. - - """ - - # With Core Graphics on Mac, it's not possible to show sash feedback, - # so we'll always use live update instead. - - if wx.Platform == "__WXMAC__": - return True - else: - return (manager.GetAGWFlags() & AUI_MGR_USE_NATIVE_MINIFRAMES) == AUI_MGR_USE_NATIVE_MINIFRAMES - - -def GetManager(window): - """ - This function will return the aui manager for a given window. - - :param Window `window`: this parameter should be any child window or grand-child - window (and so on) of the frame/window managed by :class:`AuiManager`. The window - does not need to be managed by the manager itself, nor does it even need - to be a child or sub-child of a managed window. It must however be inside - the window hierarchy underneath the managed window. - """ - - if not isinstance(wx.GetTopLevelParent(window), AuiFloatingFrame): - if isinstance(window, auibar.AuiToolBar): - return window.GetAuiManager() - - evt = AuiManagerEvent(wxEVT_AUI_FIND_MANAGER) - evt.SetManager(None) - evt.ResumePropagation(wx.EVENT_PROPAGATE_MAX) - - if not window.GetEventHandler().ProcessEvent(evt): - return None - - return evt.GetManager() - - -# ---------------------------------------------------------------------------- # - -class AuiManager(wx.EvtHandler): - """ - AuiManager manages the panes associated with it for a particular :class:`Frame`, - using a pane's :class:`AuiManager` information to determine each pane's docking and - floating behavior. :class:`AuiManager` uses wxPython's sizer mechanism to plan the - layout of each frame. It uses a replaceable dock art class to do all drawing, - so all drawing is localized in one area, and may be customized depending on an - applications' specific needs. - - :class:`AuiManager` works as follows: the programmer adds panes to the class, or makes - changes to existing pane properties (dock position, floating state, show state, etc...). - To apply these changes, the :meth:`AuiManager.Update() ` function is called. This batch - processing can be used to avoid flicker, by modifying more than one pane at a time, - and then "committing" all of the changes at once by calling `Update()`. - - Panes can be added quite easily:: - - text1 = wx.TextCtrl(self, -1) - text2 = wx.TextCtrl(self, -1) - self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One")) - self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two")) - - self._mgr.Update() - - - Later on, the positions can be modified easily. The following will float an - existing pane in a tool window:: - - self._mgr.GetPane(text1).Float() - - - **Layers, Rows and Directions, Positions:** - - Inside AUI, the docking layout is figured out by checking several pane parameters. - Four of these are important for determining where a pane will end up. - - **Direction** - Each docked pane has a direction, `Top`, `Bottom`, `Left`, `Right`, or `Center`. - This is fairly self-explanatory. The pane will be placed in the location specified - by this variable. - - **Position** - More than one pane can be placed inside of a "dock". Imagine two panes - being docked on the left side of a window. One pane can be placed over another. - In proportionally managed docks, the pane position indicates it's sequential position, - starting with zero. So, in our scenario with two panes docked on the left side, the - top pane in the dock would have position 0, and the second one would occupy position 1. - - **Row** - A row can allow for two docks to be placed next to each other. One of the most - common places for this to happen is in the toolbar. Multiple toolbar rows are allowed, - the first row being in row 0, and the second in row 1. Rows can also be used on - vertically docked panes. - - **Layer** - A layer is akin to an onion. Layer 0 is the very center of the managed pane. - Thus, if a pane is in layer 0, it will be closest to the center window (also sometimes - known as the "content window"). Increasing layers "swallow up" all layers of a lower - value. This can look very similar to multiple rows, but is different because all panes - in a lower level yield to panes in higher levels. The best way to understand layers - is by running the AUI sample (`AUI.py`). - """ - - def __init__(self, managed_window=None, agwFlags=None): - """ - Default class constructor. - - :param Window `managed_window`: specifies the window which should be managed; - :param integer `agwFlags`: specifies options which allow the frame management behavior to be - modified. `agwFlags` can be a combination of the following style bits: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_MGR_ALLOW_FLOATING`` Allow floating of panes - ``AUI_MGR_ALLOW_ACTIVE_PANE`` If a pane becomes active, "highlight" it in the interface - ``AUI_MGR_TRANSPARENT_DRAG`` If the platform supports it, set transparency on a floating pane while it is dragged by the user - ``AUI_MGR_TRANSPARENT_HINT`` If the platform supports it, show a transparent hint window when the user is about to dock a floating pane - ``AUI_MGR_VENETIAN_BLINDS_HINT`` Show a "venetian blind" effect when the user is about to dock a floating pane - ``AUI_MGR_RECTANGLE_HINT`` Show a rectangle hint effect when the user is about to dock a floating pane - ``AUI_MGR_HINT_FADE`` If the platform supports it, the hint window will fade in and out - ``AUI_MGR_NO_VENETIAN_BLINDS_FADE`` Disables the "venetian blind" fade in and out - ``AUI_MGR_LIVE_RESIZE`` Live resize when the user drag a sash - ``AUI_MGR_ANIMATE_FRAMES`` Fade-out floating panes when they are closed (all platforms which support frames transparency) - and show a moving rectangle when they are docked (Windows < Vista and GTK only) - ``AUI_MGR_AERO_DOCKING_GUIDES`` Use the new Aero-style bitmaps as docking guides - ``AUI_MGR_PREVIEW_MINIMIZED_PANES`` Slide in and out minimized panes to preview them - ``AUI_MGR_WHIDBEY_DOCKING_GUIDES`` Use the new Whidbey-style bitmaps as docking guides - ``AUI_MGR_SMOOTH_DOCKING`` Performs a "smooth" docking of panes (a la PyQT) - ``AUI_MGR_USE_NATIVE_MINIFRAMES`` Use miniframes with native caption bar as floating panes instead or custom drawn caption bars (forced on wxMAC) - ``AUI_MGR_AUTONB_NO_CAPTION`` Panes that merge into an automatic notebook will not have the pane caption visible - ==================================== ================================== - - Default value for `agwFlags` is: - ``AUI_MGR_DEFAULT`` = ``AUI_MGR_ALLOW_FLOATING`` | ``AUI_MGR_TRANSPARENT_HINT`` | ``AUI_MGR_HINT_FADE`` | ``AUI_MGR_NO_VENETIAN_BLINDS_FADE`` - - .. note:: - - If using the ``AUI_MGR_USE_NATIVE_MINIFRAMES``, double-clicking on a - floating pane caption will not re-dock the pane, but simply maximize it (if - :meth:`AuiPaneInfo.MaximizeButton` has been set to ``True``) or do nothing. - - """ - - wx.EvtHandler.__init__(self) - - self._action = actionNone - self._action_window = None - self._hover_button = None - self._art = dockart.AuiDefaultDockArt() - self._hint_window = None - self._active_pane = None - self._has_maximized = False - self._has_minimized = False - - self._frame = None - self._dock_constraint_x = 0.3 - self._dock_constraint_y = 0.3 - self._reserved = None - - self._panes = [] - self._docks = [] - self._uiparts = [] - - self._guides = [] - self._notebooks = [] - - self._masterManager = None - self._currentDragItem = -1 - self._lastknowndocks = {} - - self._hint_fadetimer = wx.Timer(self, wx.ID_ANY) - self._hint_fademax = 50 - self._last_hint = wx.Rect() - - self._from_move = False - self._last_rect = wx.Rect() - - if agwFlags is None: - agwFlags = AUI_MGR_DEFAULT - - self._agwFlags = agwFlags - self._is_docked = (False, wx.RIGHT, wx.TOP, 0) - self._snap_limits = (15, 15) - - if wx.Platform == "__WXMSW__": - self._animation_step = 30.0 - else: - self._animation_step = 5.0 - - self._hint_rect = wx.Rect() - - self._preview_timer = wx.Timer(self, wx.ID_ANY) - self._sliding_frame = None - - self._autoNBTabArt = tabart.AuiDefaultTabArt() - self._autoNBStyle = AUI_NB_DEFAULT_STYLE | AUI_NB_BOTTOM | \ - AUI_NB_SUB_NOTEBOOK | AUI_NB_TAB_EXTERNAL_MOVE - self._autoNBStyle -= AUI_NB_DRAW_DND_TAB - - if managed_window: - self.SetManagedWindow(managed_window) - - self.Bind(wx.EVT_PAINT, self.OnPaint) - self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) - self.Bind(wx.EVT_SIZE, self.OnSize) - self.Bind(wx.EVT_SET_CURSOR, self.OnSetCursor) - self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) - self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick) - self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) - self.Bind(wx.EVT_MOTION, self.OnMotion) - self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) - self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus) - self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnCaptureLost) - self.Bind(wx.EVT_TIMER, self.OnHintFadeTimer, self._hint_fadetimer) - self.Bind(wx.EVT_TIMER, self.SlideIn, self._preview_timer) - self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) - - self.Bind(wx.EVT_MOVE, self.OnMove) - self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChanged) - - self.Bind(EVT_AUI_PANE_BUTTON, self.OnPaneButton) - self.Bind(EVT_AUI_RENDER, self.OnRender) - self.Bind(EVT_AUI_FIND_MANAGER, self.OnFindManager) - self.Bind(EVT_AUI_PANE_MIN_RESTORE, self.OnRestoreMinimizedPane) - self.Bind(EVT_AUI_PANE_DOCKED, self.OnPaneDocked) - - self.Bind(auibook.EVT_AUINOTEBOOK_BEGIN_DRAG, self.OnTabBeginDrag) - self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnTabPageClose) - self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnTabSelected) - - - def CreateFloatingFrame(self, parent, pane_info): - """ - Creates a floating frame for the windows. - - :param Window `parent`: the floating frame parent; - :param `pane_info`: the :class:`AuiPaneInfo` class with all the pane's information. - """ - - return AuiFloatingFrame(parent, self, pane_info) - - - def CanDockPanel(self, p): - """ - Returns whether a pane can be docked or not. - - :param `p`: the :class:`AuiPaneInfo` class with all the pane's information. - """ - - # is the pane dockable? - if not p.IsDockable(): - return False - - # if a key modifier is pressed while dragging the frame, - # don't dock the window - return not (wx.GetKeyState(wx.WXK_CONTROL) or wx.GetKeyState(wx.WXK_ALT)) - - - def GetPaneByWidget(self, window): - """ - This version of :meth:`GetPane` looks up a pane based on a 'pane window'. - - :param `window`: a :class:`Window` derived window. - - :see: :meth:`~AuiManager.GetPane` - """ - - for p in self._panes: - if p.window == window: - return p - - return NonePaneInfo - - - def GetPaneByName(self, name): - """ - This version of :meth:`GetPane` looks up a pane based on a 'pane name'. - - :param string `name`: the pane name. - - :see: :meth:`GetPane` - """ - - for p in self._panes: - if p.name == name: - return p - - return NonePaneInfo - - - def GetPane(self, item): - """ - Looks up a :class:`AuiPaneInfo` structure based on the supplied window pointer. Upon failure, - :meth:`GetPane` returns an empty :class:`AuiPaneInfo`, a condition which can be checked - by calling :meth:`AuiPaneInfo.IsOk() `. - - The pane info's structure may then be modified. Once a pane's info is modified, :meth:`Update` - must be called to realize the changes in the UI. - - :param `item`: either a pane name or a :class:`Window`. - """ - - if isinstance(item, basestring): - return self.GetPaneByName(item) - else: - return self.GetPaneByWidget(item) - - - def GetAllPanes(self): - """ Returns a reference to all the pane info structures. """ - - return self._panes - - - def ShowPane(self, window, show): - """ - Shows or hides a pane based on the window passed as input. - - :param Window `window`: any subclass or derivation of :class:`Window`; - :param bool `show`: ``True`` to show the pane, ``False`` otherwise. - """ - - p = self.GetPane(window) - - if p.IsOk(): - if p.IsNotebookPage(): - if show: - - notebook = self._notebooks[p.notebook_id] - id = notebook.GetPageIndex(p.window) - if id >= 0: - notebook.SetSelection(id) - self.ShowPane(notebook, True) - - else: - p.Show(show) - - if p.frame: - p.frame.Raise() - - self.Update() - - - def HitTest(self, x, y): - """ - This is an internal function which determines - which UI item the specified coordinates are over. - - :param integer `x`: specifies a x position in client coordinates; - :param integer `y`: specifies a y position in client coordinates. - """ - - result = None - - for item in self._uiparts: - # we are not interested in typeDock, because this space - # isn't used to draw anything, just for measurements - # besides, the entire dock area is covered with other - # rectangles, which we are interested in. - if item.type == AuiDockUIPart.typeDock: - continue - - # if we already have a hit on a more specific item, we are not - # interested in a pane hit. If, however, we don't already have - # a hit, returning a pane hit is necessary for some operations - if item.type in [AuiDockUIPart.typePane, AuiDockUIPart.typePaneBorder] and result: - continue - - # if the point is inside the rectangle, we have a hit - if item.rect.Contains((x, y)): - result = item - - return result - - - def PaneHitTest(self, panes, pt): - """ - Similar to :meth:`HitTest`, but it checks in which :class:`AuiManager` rectangle the - input point belongs to. - - :param `panes`: a list of :class:`AuiPaneInfo` instances; - :param Point `pt`: the mouse position. - """ - - for paneInfo in panes: - if paneInfo.IsDocked() and paneInfo.IsShown() and paneInfo.rect.Contains(pt): - return paneInfo - - return NonePaneInfo - - - # SetAGWFlags() and GetAGWFlags() allow the owner to set various - # options which are global to AuiManager - - def SetAGWFlags(self, agwFlags): - """ - This method is used to specify :class:`AuiManager` 's settings flags. - - :param integer `agwFlags`: specifies options which allow the frame management behavior - to be modified. `agwFlags` can be one of the following style bits: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_MGR_ALLOW_FLOATING`` Allow floating of panes - ``AUI_MGR_ALLOW_ACTIVE_PANE`` If a pane becomes active, "highlight" it in the interface - ``AUI_MGR_TRANSPARENT_DRAG`` If the platform supports it, set transparency on a floating pane while it is dragged by the user - ``AUI_MGR_TRANSPARENT_HINT`` If the platform supports it, show a transparent hint window when the user is about to dock a floating pane - ``AUI_MGR_VENETIAN_BLINDS_HINT`` Show a "venetian blind" effect when the user is about to dock a floating pane - ``AUI_MGR_RECTANGLE_HINT`` Show a rectangle hint effect when the user is about to dock a floating pane - ``AUI_MGR_HINT_FADE`` If the platform supports it, the hint window will fade in and out - ``AUI_MGR_NO_VENETIAN_BLINDS_FADE`` Disables the "venetian blind" fade in and out - ``AUI_MGR_LIVE_RESIZE`` Live resize when the user drag a sash - ``AUI_MGR_ANIMATE_FRAMES`` Fade-out floating panes when they are closed (all platforms which support frames transparency) - and show a moving rectangle when they are docked (Windows < Vista and GTK only) - ``AUI_MGR_AERO_DOCKING_GUIDES`` Use the new Aero-style bitmaps as docking guides - ``AUI_MGR_PREVIEW_MINIMIZED_PANES`` Slide in and out minimized panes to preview them - ``AUI_MGR_WHIDBEY_DOCKING_GUIDES`` Use the new Whidbey-style bitmaps as docking guides - ``AUI_MGR_SMOOTH_DOCKING`` Performs a "smooth" docking of panes (a la PyQT) - ``AUI_MGR_USE_NATIVE_MINIFRAMES`` Use miniframes with native caption bar as floating panes instead or custom drawn caption bars (forced on wxMAC) - ``AUI_MGR_AUTONB_NO_CAPTION`` Panes that merge into an automatic notebook will not have the pane caption visible - ==================================== ================================== - - .. note:: - - If using the ``AUI_MGR_USE_NATIVE_MINIFRAMES``, double-clicking on a - floating pane caption will not re-dock the pane, but simply maximize it (if - :meth:`AuiPaneInfo.MaximizeButton` has been set to ``True``) or do nothing. - - """ - - self._agwFlags = agwFlags - - if len(self._guides) > 0: - self.CreateGuideWindows() - - if self._hint_window and agwFlags & AUI_MGR_RECTANGLE_HINT == 0: - self.CreateHintWindow() - - - def GetAGWFlags(self): - """ - Returns the current manager's flags. - - :see: :meth:`SetAGWFlags` for a list of possible :class:`AuiManager` flags. - """ - - return self._agwFlags - - - def SetManagedWindow(self, managed_window): - """ - Called to specify the frame or window which is to be managed by :class:`AuiManager`. - Frame management is not restricted to just frames. Child windows or custom - controls are also allowed. - - :param Window `managed_window`: specifies the window which should be managed by - the AUI manager. - """ - - if not managed_window: - raise Exception("Specified managed window must be non-null. ") - - self.UnInit() - - self._frame = managed_window - self._frame.PushEventHandler(self) - - # if the owner is going to manage an MDI parent frame, - # we need to add the MDI client window as the default - # center pane - - if isinstance(self._frame, wx.MDIParentFrame): - mdi_frame = self._frame - client_window = mdi_frame.GetClientWindow() - - if not client_window: - raise Exception("Client window is None!") - - self.AddPane(client_window, AuiPaneInfo().Name("mdiclient"). - CenterPane().PaneBorder(False)) - - elif isinstance(self._frame, tabmdi.AuiMDIParentFrame): - - mdi_frame = self._frame - client_window = mdi_frame.GetClientWindow() - - if not client_window: - raise Exception("Client window is None!") - - self.AddPane(client_window, AuiPaneInfo().Name("mdiclient"). - CenterPane().PaneBorder(False)) - - - def GetManagedWindow(self): - """ Returns the window being managed by :class:`AuiManager`. """ - - return self._frame - - - def SetFrame(self, managed_window): - """ - Called to specify the frame or window which is to be managed by :class:`AuiManager`. - Frame management is not restricted to just frames. Child windows or custom - controls are also allowed. - - :param Window `managed_window`: specifies the window which should be managed by - the AUI manager. - - .. deprecated:: 0.6 - This method is now deprecated, use :meth:`SetManagedWindow` instead. - """ - - DeprecationWarning("This method is deprecated, use SetManagedWindow instead.") - return self.SetManagedWindow(managed_window) - - - def GetFrame(self): - """ - Returns the window being managed by :class:`AuiManager`. - - .. deprecated:: 0.6 - This method is now deprecated, use :meth:`GetManagedWindow` instead. - """ - - DeprecationWarning("This method is deprecated, use GetManagedWindow instead.") - return self._frame - - - def CreateGuideWindows(self): - """ Creates the VS2005 HUD guide windows. """ - - self.DestroyGuideWindows() - - self._guides.append(AuiDockingGuideInfo().Left(). - Host(AuiSingleDockingGuide(self._frame, wx.LEFT))) - self._guides.append(AuiDockingGuideInfo().Top(). - Host(AuiSingleDockingGuide(self._frame, wx.TOP))) - self._guides.append(AuiDockingGuideInfo().Right(). - Host(AuiSingleDockingGuide(self._frame, wx.RIGHT))) - self._guides.append(AuiDockingGuideInfo().Bottom(). - Host(AuiSingleDockingGuide(self._frame, wx.BOTTOM))) - self._guides.append(AuiDockingGuideInfo().Centre(). - Host(AuiCenterDockingGuide(self._frame))) - - - def DestroyGuideWindows(self): - """ Destroys the VS2005 HUD guide windows. """ - - for guide in self._guides: - if guide.host: - guide.host.Destroy() - - self._guides = [] - - - def CreateHintWindow(self): - """ Creates the standard wxAUI hint window. """ - - self.DestroyHintWindow() - - self._hint_window = AuiDockingHintWindow(self._frame) - self._hint_window.SetBlindMode(self._agwFlags) - - - def DestroyHintWindow(self): - """ Destroys the standard wxAUI hint window. """ - - if self._hint_window: - - self._hint_window.Destroy() - self._hint_window = None - - - def UnInit(self): - """ - Uninitializes the framework and should be called before a managed frame or - window is destroyed. :meth:`UnInit` is usually called in the managed :class:`Frame` / :class:`Window` - destructor. - - It is necessary to call this function before the managed frame or window is - destroyed, otherwise the manager cannot remove its custom event handlers - from a window. - """ - - if not self._frame: - return - - for klass in [self._frame] + list(self._frame.GetChildren()): - handler = klass.GetEventHandler() - if klass is not handler: - if isinstance(handler, AuiManager): - klass.RemoveEventHandler(handler) - - - def OnDestroy(self, event) : - - if self._frame == event.GetEventObject(): - self.UnInit(); - - - def GetArtProvider(self): - """ Returns the current art provider being used. """ - - return self._art - - - def ProcessMgrEvent(self, event): - """ - Process the AUI events sent to the manager. - - :param `event`: the event to process, an instance of :class:`AuiManagerEvent`. - """ - - # first, give the owner frame a chance to override - if self._frame: - if self._frame.GetEventHandler().ProcessEvent(event): - return - - self.ProcessEvent(event) - - - def FireEvent(self, evtType, pane, canVeto=False): - """ - Fires one of the ``EVT_AUI_PANE_FLOATED`` / ``FLOATING`` / ``DOCKING`` / ``DOCKED`` / ``ACTIVATED`` event. - - :param integer `evtType`: one of the aforementioned events; - :param `pane`: the :class:`AuiPaneInfo` instance associated to this event; - :param bool `canVeto`: whether the event can be vetoed or not. - """ - - event = AuiManagerEvent(evtType) - event.SetPane(pane) - event.SetCanVeto(canVeto) - self.ProcessMgrEvent(event) - - return event - - - def CanUseModernDockArt(self): - """ - Returns whether :class:`dockart` can be used (Windows XP / Vista / 7 only, - requires Mark Hammonds's `pywin32 `_ package). - """ - - if not _winxptheme: - return False - - # Get the size of a small close button (themed) - hwnd = self._frame.GetHandle() - hTheme = winxptheme.OpenThemeData(hwnd, "Window") - - if not hTheme: - return False - - return True - - - def SetArtProvider(self, art_provider): - """ - Instructs :class:`AuiManager` to use art provider specified by the parameter - `art_provider` for all drawing calls. This allows plugable look-and-feel - features. - - :param `art_provider`: a AUI dock art provider. - - :note: The previous art provider object, if any, will be deleted by :class:`AuiManager`. - """ - - # delete the last art provider, if any - del self._art - - # assign the new art provider - self._art = art_provider - - for pane in self.GetAllPanes(): - if pane.IsFloating() and pane.frame: - pane.frame._mgr.SetArtProvider(art_provider) - pane.frame._mgr.Update() - - - def AddPane(self, window, arg1=None, arg2=None, target=None): - """ - Tells the frame manager to start managing a child window. There - are four versions of this function. The first verison allows the full spectrum - of pane parameter possibilities (:meth:`AddPane1`). The second version is used for - simpler user interfaces which do not require as much configuration (:meth:`AddPane2`). - The :meth:`AddPane3` version allows a drop position to be specified, which will determine - where the pane will be added. The :meth:`AddPane4` version allows to turn the target - :class:`AuiPaneInfo` pane into a notebook and the added pane into a page. - - In your code, simply call :meth:`AddPane`. - - :param Window `window`: the child window to manage; - :param `arg1`: a :class:`AuiPaneInfo` or an integer value (direction); - :param `arg2`: a :class:`AuiPaneInfo` or a :class:`Point` (drop position); - :param `target`: a :class:`AuiPaneInfo` to be turned into a notebook - and new pane added to it as a page. (additionally, target can be any pane in - an existing notebook) - """ - - if target in self._panes: - return self.AddPane4(window, arg1, target) - - if type(arg1) == type(1): - # This Is Addpane2 - if arg1 is None: - arg1 = wx.LEFT - if arg2 is None: - arg2 = "" - return self.AddPane2(window, arg1, arg2) - else: - if isinstance(arg2, wx.Point): - return self.AddPane3(window, arg1, arg2) - else: - return self.AddPane1(window, arg1) - - - def AddPane1(self, window, pane_info): - """ See comments on :meth:`AddPane`. """ - - # check if the pane has a valid window - if not window: - return False - - # check if the pane already exists - if self.GetPane(pane_info.window).IsOk(): - return False - - # check if the pane name already exists, this could reveal a - # bug in the library user's application - already_exists = False - if pane_info.name != "" and self.GetPane(pane_info.name).IsOk(): - warnings.warn("A pane with the name '%s' already exists in the manager!"%pane_info.name) - already_exists = True - - # if the new pane is docked then we should undo maximize - if pane_info.IsDocked(): - self.RestoreMaximizedPane() - - self._panes.append(pane_info) - pinfo = self._panes[-1] - - # set the pane window - pinfo.window = window - - # if the pane's name identifier is blank, create a random string - if pinfo.name == "" or already_exists: - pinfo.name = ("%s%08x%08x%08x")%(pinfo.window.GetName(), time.time(), - time.clock(), len(self._panes)) - - # set initial proportion (if not already set) - if pinfo.dock_proportion == 0: - pinfo.dock_proportion = 100000 - - floating = isinstance(self._frame, AuiFloatingFrame) - - pinfo.buttons = [] - - if not floating and pinfo.HasMinimizeButton(): - button = AuiPaneButton(AUI_BUTTON_MINIMIZE) - pinfo.buttons.append(button) - - if not floating and pinfo.HasMaximizeButton(): - button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE) - pinfo.buttons.append(button) - - if not floating and pinfo.HasPinButton(): - button = AuiPaneButton(AUI_BUTTON_PIN) - pinfo.buttons.append(button) - - if pinfo.HasCloseButton(): - button = AuiPaneButton(AUI_BUTTON_CLOSE) - pinfo.buttons.append(button) - - if pinfo.HasGripper(): - if isinstance(pinfo.window, auibar.AuiToolBar): - # prevent duplicate gripper -- both AuiManager and AuiToolBar - # have a gripper control. The toolbar's built-in gripper - # meshes better with the look and feel of the control than ours, - # so turn AuiManager's gripper off, and the toolbar's on. - - tb = pinfo.window - pinfo.SetFlag(AuiPaneInfo.optionGripper, False) - tb.SetGripperVisible(True) - - if pinfo.window: - if pinfo.best_size == wx.Size(-1, -1): - pinfo.best_size = pinfo.window.GetClientSize() - - if isinstance(pinfo.window, wx.ToolBar): - # GetClientSize() doesn't get the best size for - # a toolbar under some newer versions of wxWidgets, - # so use GetBestSize() - pinfo.best_size = pinfo.window.GetBestSize() - - # this is needed for Win2000 to correctly fill toolbar backround - # it should probably be repeated once system colour change happens - if wx.Platform == "__WXMSW__" and pinfo.window.UseBgCol(): - pinfo.window.SetBackgroundColour(self.GetArtProvider().GetColour(AUI_DOCKART_BACKGROUND_COLOUR)) - - if pinfo.min_size != wx.Size(-1, -1): - if pinfo.best_size.x < pinfo.min_size.x: - pinfo.best_size.x = pinfo.min_size.x - if pinfo.best_size.y < pinfo.min_size.y: - pinfo.best_size.y = pinfo.min_size.y - - self._panes[-1] = pinfo - if isinstance(window, auibar.AuiToolBar): - window.SetAuiManager(self) - - return True - - - def AddPane2(self, window, direction, caption): - """ See comments on :meth:`AddPane`. """ - - pinfo = AuiPaneInfo() - pinfo.Caption(caption) - - if direction == wx.TOP: - pinfo.Top() - elif direction == wx.BOTTOM: - pinfo.Bottom() - elif direction == wx.LEFT: - pinfo.Left() - elif direction == wx.RIGHT: - pinfo.Right() - elif direction == wx.CENTER: - pinfo.CenterPane() - - return self.AddPane(window, pinfo) - - - def AddPane3(self, window, pane_info, drop_pos): - """ See comments on :meth:`AddPane`. """ - - if not self.AddPane(window, pane_info): - return False - - pane = self.GetPane(window) - indx = self._panes.index(pane) - - ret, pane = self.DoDrop(self._docks, self._panes, pane, drop_pos, wx.Point(0, 0)) - self._panes[indx] = pane - - return True - - - def AddPane4(self, window, pane_info, target): - """ See comments on :meth:`AddPane`. """ - - if not self.AddPane(window, pane_info): - return False - - paneInfo = self.GetPane(window) - - if not paneInfo.IsNotebookDockable(): - return self.AddPane1(window, pane_info) - if not target.IsNotebookDockable() and not target.IsNotebookControl(): - return self.AddPane1(window, pane_info) - - if not target.HasNotebook(): - self.CreateNotebookBase(self._panes, target) - - # Add new item to notebook - paneInfo.NotebookPage(target.notebook_id) - - # we also want to remove our captions sometimes - self.RemoveAutoNBCaption(paneInfo) - self.UpdateNotebook() - - return True - - - def InsertPane(self, window, pane_info, insert_level=AUI_INSERT_PANE): - """ - This method is used to insert either a previously unmanaged pane window - into the frame manager, or to insert a currently managed pane somewhere else. - :meth:`InsertPane` will push all panes, rows, or docks aside and insert the window - into the position specified by `pane_info`. - - Because `pane_info` can specify either a pane, dock row, or dock layer, the - `insert_level` parameter is used to disambiguate this. The parameter `insert_level` - can take a value of ``AUI_INSERT_PANE``, ``AUI_INSERT_ROW`` or ``AUI_INSERT_DOCK``. - - :param Window `window`: the window to be inserted and managed; - :param `pane_info`: the insert location for the new window; - :param integer `insert_level`: the insertion level of the new pane. - """ - - if not window: - raise Exception("Invalid window passed to InsertPane.") - - # shift the panes around, depending on the insert level - if insert_level == AUI_INSERT_PANE: - self._panes = DoInsertPane(self._panes, pane_info.dock_direction, - pane_info.dock_layer, pane_info.dock_row, - pane_info.dock_pos) - - elif insert_level == AUI_INSERT_ROW: - self._panes = DoInsertDockRow(self._panes, pane_info.dock_direction, - pane_info.dock_layer, pane_info.dock_row) - - elif insert_level == AUI_INSERT_DOCK: - self._panes = DoInsertDockLayer(self._panes, pane_info.dock_direction, - pane_info.dock_layer) - - # if the window already exists, we are basically just moving/inserting the - # existing window. If it doesn't exist, we need to add it and insert it - existing_pane = self.GetPane(window) - indx = self._panes.index(existing_pane) - - if not existing_pane.IsOk(): - - return self.AddPane(window, pane_info) - - else: - - if pane_info.IsFloating(): - existing_pane.Float() - if pane_info.floating_pos != wx.Point(-1, -1): - existing_pane.FloatingPosition(pane_info.floating_pos) - if pane_info.floating_size != wx.Size(-1, -1): - existing_pane.FloatingSize(pane_info.floating_size) - else: - # if the new pane is docked then we should undo maximize - self.RestoreMaximizedPane() - - existing_pane.Direction(pane_info.dock_direction) - existing_pane.Layer(pane_info.dock_layer) - existing_pane.Row(pane_info.dock_row) - existing_pane.Position(pane_info.dock_pos) - - self._panes[indx] = existing_pane - - return True - - - def DetachPane(self, window): - """ - Tells the :class:`AuiManager` to stop managing the pane specified - by `window`. The window, if in a floated frame, is reparented to the frame - managed by :class:`AuiManager`. - - :param Window `window`: the window to be un-managed. - """ - - for p in self._panes: - if p.window == window: - if p.frame: - # we have a floating frame which is being detached. We need to - # reparent it to self._frame and destroy the floating frame - - # reduce flicker - p.window.SetSize((1, 1)) - if p.frame.IsShown(): - p.frame.Show(False) - - if self._action_window == p.frame: - self._action_window = None - - # reparent to self._frame and destroy the pane - p.window.Reparent(self._frame) - p.frame.SetSizer(None) - p.frame.Destroy() - p.frame = None - - elif p.IsNotebookPage(): - notebook = self._notebooks[p.notebook_id] - id = notebook.GetPageIndex(p.window) - notebook.RemovePage(id) - - # make sure there are no references to this pane in our uiparts, - # just in case the caller doesn't call Update() immediately after - # the DetachPane() call. This prevets obscure crashes which would - # happen at window repaint if the caller forgets to call Update() - counter = 0 - for pi in xrange(len(self._uiparts)): - part = self._uiparts[counter] - if part.pane == p: - self._uiparts.pop(counter) - counter -= 1 - - counter += 1 - - self._panes.remove(p) - return True - - return False - - - def ClosePane(self, pane_info): - """ - Destroys or hides the pane depending on its flags. - - :param `pane_info`: a :class:`AuiPaneInfo` instance. - """ - # if we were maximized, restore - if pane_info.IsMaximized(): - self.RestorePane(pane_info) - - if pane_info.frame: - if self._agwFlags & AUI_MGR_ANIMATE_FRAMES: - pane_info.frame.FadeOut() - - # first, hide the window - if pane_info.window and pane_info.window.IsShown(): - pane_info.window.Show(False) - - # make sure that we are the parent of this window - if pane_info.window and pane_info.window.GetParent() != self._frame: - pane_info.window.Reparent(self._frame) - - # if we have a frame, destroy it - if pane_info.frame: - pane_info.frame.Destroy() - pane_info.frame = None - - elif pane_info.IsNotebookPage(): - # if we are a notebook page, remove ourselves... - # the code would index out of bounds - # if the last page of a sub-notebook was closed - # because the notebook would be deleted, before this - # code is executed. - # This code just prevents an out-of bounds error. - if self._notebooks: - nid = pane_info.notebook_id - if nid >= 0 and nid < len(self._notebooks): - notebook = self._notebooks[nid] - page_idx = notebook.GetPageIndex(pane_info.window) - if page_idx >= 0: - notebook.RemovePage(page_idx) - - # now we need to either destroy or hide the pane - to_destroy = 0 - if pane_info.IsDestroyOnClose(): - to_destroy = pane_info.window - self.DetachPane(to_destroy) - else: - if isinstance(pane_info.window, auibar.AuiToolBar) and pane_info.IsFloating(): - tb = pane_info.window - if pane_info.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]: - tb.SetAGWWindowStyleFlag(tb.GetAGWWindowStyleFlag() | AUI_TB_VERTICAL) - - #pane_info.Dock().Hide() - # We don't want to dock the pane when it's closed. Just hide - # it so that if it's currently floated, it's re-floated the - # next time it is shown. - pane_info.Hide() - - if pane_info.IsNotebookControl(): - - notebook = self._notebooks[pane_info.notebook_id] - while notebook.GetPageCount(): - window = notebook.GetPage(0) - notebook.RemovePage(0) - info = self.GetPane(window) - if info.IsOk(): - info.notebook_id = -1 - info.dock_direction = AUI_DOCK_NONE - # Note: this could change our paneInfo reference ... - self.ClosePane(info) - - if to_destroy: - to_destroy.Destroy() - - - def MaximizePane(self, pane_info, savesizes=True): - """ - Maximizes the input pane. - - :param `pane_info`: a :class:`AuiPaneInfo` instance. - :param bool `savesizes`: whether to save previous dock sizes. - """ - - if savesizes: - self.SavePreviousDockSizes(pane_info) - - for p in self._panes: - - # save hidden state - p.SetFlag(p.savedHiddenState, p.HasFlag(p.optionHidden)) - - if not p.IsToolbar() and not p.IsFloating(): - p.Restore() - - # hide the pane, because only the newly - # maximized pane should show - p.Hide() - - pane_info.previousDockPos = pane_info.dock_pos - - # mark ourselves maximized - pane_info.Maximize() - pane_info.Show() - self._has_maximized = True - - # last, show the window - if pane_info.window and not pane_info.window.IsShown(): - pane_info.window.Show(True) - - - def SavePreviousDockSizes(self, pane_info): - """ - Stores the previous dock sizes, to be used in a "restore" action later. - - :param `pane_info`: a :class:`AuiPaneInfo` instance. - """ - - for d in self._docks: - if not d.toolbar: - for p in d.panes: - p.previousDockSize = d.size - if pane_info is not p: - p.SetFlag(p.needsRestore, True) - - - def RestorePane(self, pane_info): - """ - Restores the input pane from a previous maximized or minimized state. - - :param `pane_info`: a :class:`AuiPaneInfo` instance. - """ - - # restore all the panes - for p in self._panes: - if not p.IsToolbar(): - p.SetFlag(p.optionHidden, p.HasFlag(p.savedHiddenState)) - - pane_info.SetFlag(pane_info.needsRestore, True) - - # mark ourselves non-maximized - pane_info.Restore() - self._has_maximized = False - self._has_minimized = False - - # last, show the window - if pane_info.window and not pane_info.window.IsShown(): - pane_info.window.Show(True) - - - def RestoreMaximizedPane(self): - """ Restores the current maximized pane (if any). """ - - # restore all the panes - for p in self._panes: - if p.IsMaximized(): - self.RestorePane(p) - break - - - def ActivatePane(self, window): - """ - Activates the pane to which `window` is associated. - - :param `window`: a :class:`Window` derived window. - """ - - if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE: - while window: - ret, self._panes = SetActivePane(self._panes, window) - if ret: - break - - window = window.GetParent() - - self.RefreshCaptions() - self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, window, canVeto=False) - - - def CreateNotebook(self): - """ - Creates an automatic :class:`~lib.agw.aui.auibook.AuiNotebook` when a pane is docked on - top of another pane. - """ - - notebook = auibook.AuiNotebook(self._frame, -1, wx.Point(0, 0), wx.Size(0, 0), agwStyle=self._autoNBStyle) - - # This is so we can get the tab-drag event. - notebook.GetAuiManager().SetMasterManager(self) - notebook.SetArtProvider(self._autoNBTabArt.Clone()) - self._notebooks.append(notebook) - - return notebook - - - def SetAutoNotebookTabArt(self, art): - """ - Sets the default tab art provider for automatic notebooks. - - :param `art`: a tab art provider. - """ - - for nb in self._notebooks: - nb.SetArtProvider(art.Clone()) - nb.Refresh() - nb.Update() - - self._autoNBTabArt = art - - - def GetAutoNotebookTabArt(self): - """ Returns the default tab art provider for automatic notebooks. """ - - return self._autoNBTabArt - - - def SetAutoNotebookStyle(self, agwStyle): - """ - Sets the default AGW-specific window style for automatic notebooks. - - :param integer `agwStyle`: the underlying :class:`~lib.agw.aui.auibook.AuiNotebook` window style. - This can be a combination of the following bits: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook - ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet. - ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet. - ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook - ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab - ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging - ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control - ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width - ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed - ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available - ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar - ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab - ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs - ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close :class:`~lib.agw.aui.auibook.AuiNotebook` tabs by mouse middle button click - ``AUI_NB_SUB_NOTEBOOK`` This style is used by :class:`AuiManager` to create automatic AuiNotebooks - ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present - ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows - ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items - ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser) - ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less - full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages - ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default) - ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs - ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle - ==================================== ================================== - - """ - - for nb in self._notebooks: - nb.SetAGWWindowStyleFlag(agwStyle) - nb.Refresh() - nb.Update() - - self._autoNBStyle = agwStyle - - - def GetAutoNotebookStyle(self): - """ - Returns the default AGW-specific window style for automatic notebooks. - - :see: :meth:`SetAutoNotebookStyle` method for a list of possible styles. - """ - - return self._autoNBStyle - - - def SavePaneInfo(self, pane): - """ - This method is similar to :meth:`SavePerspective`, with the exception - that it only saves information about a single pane. It is used in - combination with :meth:`LoadPaneInfo`. - - :param `pane`: a :class:`AuiPaneInfo` instance to save. - """ - - result = "name=" + EscapeDelimiters(pane.name) + ";" - result += "caption=" + EscapeDelimiters(pane.caption) + ";" - - result += "state=%u;"%pane.state - result += "dir=%d;"%pane.dock_direction - result += "layer=%d;"%pane.dock_layer - result += "row=%d;"%pane.dock_row - result += "pos=%d;"%pane.dock_pos - result += "prop=%d;"%pane.dock_proportion - result += "bestw=%d;"%pane.best_size.x - result += "besth=%d;"%pane.best_size.y - result += "minw=%d;"%pane.min_size.x - result += "minh=%d;"%pane.min_size.y - result += "maxw=%d;"%pane.max_size.x - result += "maxh=%d;"%pane.max_size.y - result += "floatx=%d;"%pane.floating_pos.x - result += "floaty=%d;"%pane.floating_pos.y - result += "floatw=%d;"%pane.floating_size.x - result += "floath=%d;"%pane.floating_size.y - result += "notebookid=%d;"%pane.notebook_id - result += "transparent=%d"%pane.transparent - - return result - - - def LoadPaneInfo(self, pane_part, pane): - """ - This method is similar to to :meth:`LoadPerspective`, with the exception that - it only loads information about a single pane. It is used in combination - with :meth:`SavePaneInfo`. - - :param string `pane_part`: the string to analyze; - :param `pane`: the :class:`AuiPaneInfo` structure in which to load `pane_part`. - """ - - # replace escaped characters so we can - # split up the string easily - pane_part = pane_part.replace("\\|", "\a") - pane_part = pane_part.replace("\\;", "\b") - - options = pane_part.split(";") - for items in options: - - val_name, value = items.split("=") - val_name = val_name.strip() - - if val_name == "name": - pane.name = value - elif val_name == "caption": - pane.caption = value - elif val_name == "state": - pane.state = int(value) - elif val_name == "dir": - pane.dock_direction = int(value) - elif val_name == "layer": - pane.dock_layer = int(value) - elif val_name == "row": - pane.dock_row = int(value) - elif val_name == "pos": - pane.dock_pos = int(value) - elif val_name == "prop": - pane.dock_proportion = int(value) - elif val_name == "bestw": - pane.best_size.x = int(value) - elif val_name == "besth": - pane.best_size.y = int(value) - pane.best_size = wx.Size(pane.best_size.x, pane.best_size.y) - elif val_name == "minw": - pane.min_size.x = int(value) - elif val_name == "minh": - pane.min_size.y = int(value) - pane.min_size = wx.Size(pane.min_size.x, pane.min_size.y) - elif val_name == "maxw": - pane.max_size.x = int(value) - elif val_name == "maxh": - pane.max_size.y = int(value) - pane.max_size = wx.Size(pane.max_size.x, pane.max_size.y) - elif val_name == "floatx": - pane.floating_pos.x = int(value) - elif val_name == "floaty": - pane.floating_pos.y = int(value) - pane.floating_pos = wx.Point(pane.floating_pos.x, pane.floating_pos.y) - elif val_name == "floatw": - pane.floating_size.x = int(value) - elif val_name == "floath": - pane.floating_size.y = int(value) - pane.floating_size = wx.Size(pane.floating_size.x, pane.floating_size.y) - elif val_name == "notebookid": - pane.notebook_id = int(value) - elif val_name == "transparent": - pane.transparent = int(value) - else: - raise Exception("Bad perspective string") - - # replace escaped characters so we can - # split up the string easily - pane.name = pane.name.replace("\a", "|") - pane.name = pane.name.replace("\b", ";") - pane.caption = pane.caption.replace("\a", "|") - pane.caption = pane.caption.replace("\b", ";") - pane_part = pane_part.replace("\a", "|") - pane_part = pane_part.replace("\b", ";") - - return pane - - - def SavePerspective(self): - """ - Saves the entire user interface layout into an encoded string, which can then - be stored by the application (probably using :class:`Config`). - - When a perspective is restored using :meth:`LoadPerspective`, the entire user - interface will return to the state it was when the perspective was saved. - """ - - result = "layout2|" - - for pane in self._panes: - result += self.SavePaneInfo(pane) + "|" - - for dock in self._docks: - result = result + ("dock_size(%d,%d,%d)=%d|")%(dock.dock_direction, - dock.dock_layer, - dock.dock_row, - dock.size) - return result - - - def LoadPerspective(self, layout, update=True, restorecaption=False): - """ - Loads a layout which was saved with :meth:`SavePerspective`. - - If the `update` flag parameter is ``True``, :meth:`Update` will be - automatically invoked, thus realizing the saved perspective on screen. - - :param string `layout`: a string which contains a saved AUI layout; - :param bool `update`: whether to update immediately the window or not; - :param bool `restorecaption`: ``False``, restore from persist storage, - otherwise use the caption defined in code. - """ - - input = layout - - # check layout string version - # 'layout1' = wxAUI 0.9.0 - wxAUI 0.9.2 - # 'layout2' = wxAUI 0.9.2 (wxWidgets 2.8) - index = input.find("|") - part = input[0:index].strip() - input = input[index+1:] - - if part != "layout2": - return False - - # mark all panes currently managed as docked and hidden - saveCapt = {} # see restorecaption param - for pane in self._panes: - pane.Dock().Hide() - saveCapt[pane.name] = pane.caption - - # clear out the dock array; this will be reconstructed - self._docks = [] - - # replace escaped characters so we can - # split up the string easily - input = input.replace("\\|", "\a") - input = input.replace("\\;", "\b") - - while 1: - - pane = AuiPaneInfo() - index = input.find("|") - pane_part = input[0:index].strip() - input = input[index+1:] - - # if the string is empty, we're done parsing - if pane_part == "": - break - - if pane_part[0:9] == "dock_size": - index = pane_part.find("=") - val_name = pane_part[0:index] - value = pane_part[index+1:] - - index = val_name.find("(") - piece = val_name[index+1:] - index = piece.find(")") - piece = piece[0:index] - - vals = piece.split(",") - dir = int(vals[0]) - layer = int(vals[1]) - row = int(vals[2]) - size = int(value) - - dock = AuiDockInfo() - dock.dock_direction = dir - dock.dock_layer = layer - dock.dock_row = row - dock.size = size - self._docks.append(dock) - - continue - - # Undo our escaping as LoadPaneInfo needs to take an unescaped - # name so it can be called by external callers - pane_part = pane_part.replace("\a", "|") - pane_part = pane_part.replace("\b", ";") - - pane = self.LoadPaneInfo(pane_part, pane) - - p = self.GetPane(pane.name) - # restore pane caption from code - if restorecaption: - if pane.name in saveCapt: - pane.Caption(saveCapt[pane.name]) - - if not p.IsOk(): - if pane.IsNotebookControl(): - # notebook controls - auto add... - self._panes.append(pane) - indx = self._panes.index(pane) - else: - # the pane window couldn't be found - # in the existing layout -- skip it - continue - - else: - indx = self._panes.index(p) - pane.window = p.window - pane.frame = p.frame - pane.buttons = p.buttons - self._panes[indx] = pane - - if isinstance(pane.window, auibar.AuiToolBar) and (pane.IsFloatable() or pane.IsDockable()): - pane.window.SetGripperVisible(True) - - for p in self._panes: - if p.IsMinimized(): - self.MinimizePane(p, False) - - if update: - self.Update() - - return True - - - def GetPanePositionsAndSizes(self, dock): - """ - Returns all the panes positions and sizes in a dock. - - :param `dock`: a :class:`AuiDockInfo` instance. - """ - - caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE) - pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE) - gripper_size = self._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE) - - positions = [] - sizes = [] - - action_pane = -1 - pane_count = len(dock.panes) - - # find the pane marked as our action pane - for pane_i in xrange(pane_count): - pane = dock.panes[pane_i] - if pane.HasFlag(AuiPaneInfo.actionPane): - if action_pane != -1: - raise Exception("Too many action panes!") - action_pane = pane_i - - # set up each panes default position, and - # determine the size (width or height, depending - # on the dock's orientation) of each pane - for pane in dock.panes: - positions.append(pane.dock_pos) - size = 0 - - if pane.HasBorder(): - size += pane_border_size*2 - - if dock.IsHorizontal(): - if pane.HasGripper() and not pane.HasGripperTop(): - size += gripper_size - - if pane.HasCaptionLeft(): - size += caption_size - - size += pane.best_size.x - - else: - if pane.HasGripper() and pane.HasGripperTop(): - size += gripper_size - - if pane.HasCaption() and not pane.HasCaptionLeft(): - size += caption_size - - size += pane.best_size.y - - sizes.append(size) - - # if there is no action pane, just return the default - # positions (as specified in pane.pane_pos) - if action_pane == -1: - return positions, sizes - - offset = 0 - for pane_i in xrange(action_pane-1, -1, -1): - amount = positions[pane_i+1] - (positions[pane_i] + sizes[pane_i]) - if amount >= 0: - offset += amount - else: - positions[pane_i] -= -amount - - offset += sizes[pane_i] - - # if the dock mode is fixed, make sure none of the panes - # overlap we will bump panes that overlap - offset = 0 - for pane_i in xrange(action_pane, pane_count): - amount = positions[pane_i] - offset - if amount >= 0: - offset += amount - else: - positions[pane_i] += -amount - - offset += sizes[pane_i] - - return positions, sizes - - - def LayoutAddPane(self, cont, dock, pane, uiparts, spacer_only): - """ - Adds a pane into the existing layout (in an existing dock). - - :param `cont`: a :class:`Sizer` object; - :param `dock`: the :class:`AuiDockInfo` structure in which to add the pane; - :param `pane`: the :class:`AuiPaneInfo` instance to add to the dock; - :param `uiparts`: a list of UI parts in the interface; - :param bool `spacer_only`: whether to add a simple spacer or a real window. - """ - - sizer_item = wx.SizerItem() - caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE) - gripper_size = self._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE) - pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE) - pane_button_size = self._art.GetMetric(AUI_DOCKART_PANE_BUTTON_SIZE) - - # find out the orientation of the item (orientation for panes - # is the same as the dock's orientation) - - if dock.IsHorizontal(): - orientation = wx.HORIZONTAL - else: - orientation = wx.VERTICAL - - # this variable will store the proportion - # value that the pane will receive - pane_proportion = pane.dock_proportion - - horz_pane_sizer = wx.BoxSizer(wx.HORIZONTAL) - vert_pane_sizer = wx.BoxSizer(wx.VERTICAL) - - if pane.HasGripper(): - - part = AuiDockUIPart() - if pane.HasGripperTop(): - sizer_item = vert_pane_sizer.Add((1, gripper_size), 0, wx.EXPAND) - else: - sizer_item = horz_pane_sizer.Add((gripper_size, 1), 0, wx.EXPAND) - - part.type = AuiDockUIPart.typeGripper - part.dock = dock - part.pane = pane - part.button = None - part.orientation = orientation - part.cont_sizer = horz_pane_sizer - part.sizer_item = sizer_item - uiparts.append(part) - - button_count = len(pane.buttons) - button_width_total = button_count*pane_button_size - if button_count >= 1: - button_width_total += 3 - - caption, captionLeft = pane.HasCaption(), pane.HasCaptionLeft() - button_count = len(pane.buttons) - - if captionLeft: - caption_sizer = wx.BoxSizer(wx.VERTICAL) - - # add pane buttons to the caption - dummy_parts = [] - for btn_id in xrange(len(pane.buttons)-1, -1, -1): - sizer_item = caption_sizer.Add((caption_size, pane_button_size), 0, wx.EXPAND) - part = AuiDockUIPart() - part.type = AuiDockUIPart.typePaneButton - part.dock = dock - part.pane = pane - part.button = pane.buttons[btn_id] - part.orientation = orientation - part.cont_sizer = caption_sizer - part.sizer_item = sizer_item - dummy_parts.append(part) - - sizer_item = caption_sizer.Add((caption_size, 1), 1, wx.EXPAND) - vert_pane_sizer = wx.BoxSizer(wx.HORIZONTAL) - - # create the caption sizer - part = AuiDockUIPart() - - part.type = AuiDockUIPart.typeCaption - part.dock = dock - part.pane = pane - part.button = None - part.orientation = orientation - part.cont_sizer = vert_pane_sizer - part.sizer_item = sizer_item - caption_part_idx = len(uiparts) - uiparts.append(part) - uiparts.extend(dummy_parts) - - elif caption: - - caption_sizer = wx.BoxSizer(wx.HORIZONTAL) - sizer_item = caption_sizer.Add((1, caption_size), 1, wx.EXPAND) - - # create the caption sizer - part = AuiDockUIPart() - - part.type = AuiDockUIPart.typeCaption - part.dock = dock - part.pane = pane - part.button = None - part.orientation = orientation - part.cont_sizer = vert_pane_sizer - part.sizer_item = sizer_item - caption_part_idx = len(uiparts) - uiparts.append(part) - - # add pane buttons to the caption - for button in pane.buttons: - sizer_item = caption_sizer.Add((pane_button_size, caption_size), 0, wx.EXPAND) - part = AuiDockUIPart() - part.type = AuiDockUIPart.typePaneButton - part.dock = dock - part.pane = pane - part.button = button - part.orientation = orientation - part.cont_sizer = caption_sizer - part.sizer_item = sizer_item - uiparts.append(part) - - if caption or captionLeft: - # if we have buttons, add a little space to the right - # of them to ease visual crowding - if button_count >= 1: - if captionLeft: - caption_sizer.Add((caption_size, 3), 0, wx.EXPAND) - else: - caption_sizer.Add((3, caption_size), 0, wx.EXPAND) - - # add the caption sizer - sizer_item = vert_pane_sizer.Add(caption_sizer, 0, wx.EXPAND) - uiparts[caption_part_idx].sizer_item = sizer_item - - # add the pane window itself - if spacer_only or not pane.window: - sizer_item = vert_pane_sizer.Add((1, 1), 1, wx.EXPAND) - else: - sizer_item = vert_pane_sizer.Add(pane.window, 1, wx.EXPAND) - vert_pane_sizer.SetItemMinSize(pane.window, (1, 1)) - - part = AuiDockUIPart() - part.type = AuiDockUIPart.typePane - part.dock = dock - part.pane = pane - part.button = None - part.orientation = orientation - part.cont_sizer = vert_pane_sizer - part.sizer_item = sizer_item - uiparts.append(part) - - # determine if the pane should have a minimum size if the pane is - # non-resizable (fixed) then we must set a minimum size. Alternatively, - # if the pane.min_size is set, we must use that value as well - - min_size = pane.min_size - if pane.IsFixed(): - if min_size == wx.Size(-1, -1): - min_size = pane.best_size - pane_proportion = 0 - - if min_size != wx.Size(-1, -1): - vert_pane_sizer.SetItemMinSize(len(vert_pane_sizer.GetChildren())-1, (min_size.x, min_size.y)) - - # add the vertical/horizontal sizer (caption, pane window) to the - # horizontal sizer (gripper, vertical sizer) - horz_pane_sizer.Add(vert_pane_sizer, 1, wx.EXPAND) - - # finally, add the pane sizer to the dock sizer - if pane.HasBorder(): - # allowing space for the pane's border - sizer_item = cont.Add(horz_pane_sizer, pane_proportion, - wx.EXPAND | wx.ALL, pane_border_size) - part = AuiDockUIPart() - part.type = AuiDockUIPart.typePaneBorder - part.dock = dock - part.pane = pane - part.button = None - part.orientation = orientation - part.cont_sizer = cont - part.sizer_item = sizer_item - uiparts.append(part) - else: - sizer_item = cont.Add(horz_pane_sizer, pane_proportion, wx.EXPAND) - - return uiparts - - - def LayoutAddDock(self, cont, dock, uiparts, spacer_only): - """ - Adds a dock into the existing layout. - - :param `cont`: a :class:`Sizer` object; - :param `dock`: the :class:`AuiDockInfo` structure to add to the layout; - :param `uiparts`: a list of UI parts in the interface; - :param bool `spacer_only`: whether to add a simple spacer or a real window. - """ - - sizer_item = wx.SizerItem() - part = AuiDockUIPart() - - sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE) - - # WHAT IS THIS?! I DON'T EVEN... - #orientation = (dock.IsHorizontal() and [wx.HORIZONTAL] or [wx.VERTICAL])[0] - orientation = wx.HORIZONTAL if dock.IsHorizontal() else wx.VERTICAL - - # resizable bottom and right docks have a sash before them - if not self._has_maximized and not dock.fixed and \ - dock.dock_direction in [AUI_DOCK_BOTTOM, AUI_DOCK_RIGHT]: - - sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND) - - part.type = AuiDockUIPart.typeDockSizer - part.orientation = orientation - part.dock = dock - part.pane = None - part.button = None - part.cont_sizer = cont - part.sizer_item = sizer_item - uiparts.append(part) - - # create the sizer for the dock - dock_sizer = wx.BoxSizer(orientation) - - # add each pane to the dock - has_maximized_pane = False - pane_count = len(dock.panes) - - if dock.fixed: - - # figure out the real pane positions we will - # use, without modifying the each pane's pane_pos member - pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock) - - offset = 0 - for pane_i in xrange(pane_count): - - pane = dock.panes[pane_i] - pane_pos = pane_positions[pane_i] - - if pane.IsMaximized(): - has_maximized_pane = True - - amount = pane_pos - offset - if amount > 0: - - if dock.IsVertical(): - sizer_item = dock_sizer.Add((1, amount), 0, wx.EXPAND) - else: - sizer_item = dock_sizer.Add((amount, 1), 0, wx.EXPAND) - - part = AuiDockUIPart() - part.type = AuiDockUIPart.typeBackground - part.dock = dock - part.pane = None - part.button = None - part.orientation = (orientation==wx.HORIZONTAL and \ - [wx.VERTICAL] or [wx.HORIZONTAL])[0] - part.cont_sizer = dock_sizer - part.sizer_item = sizer_item - uiparts.append(part) - - offset = offset + amount - - uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only) - - offset = offset + pane_sizes[pane_i] - - # at the end add a very small stretchable background area - sizer_item = dock_sizer.Add((0, 0), 1, wx.EXPAND) - part = AuiDockUIPart() - part.type = AuiDockUIPart.typeBackground - part.dock = dock - part.pane = None - part.button = None - part.orientation = orientation - part.cont_sizer = dock_sizer - part.sizer_item = sizer_item - uiparts.append(part) - - else: - - for pane_i in xrange(pane_count): - - pane = dock.panes[pane_i] - - if pane.IsMaximized(): - has_maximized_pane = True - - # if this is not the first pane being added, - # we need to add a pane sizer - if not self._has_maximized and pane_i > 0: - sizer_item = dock_sizer.Add((sash_size, sash_size), 0, wx.EXPAND) - part = AuiDockUIPart() - part.type = AuiDockUIPart.typePaneSizer - part.dock = dock - part.pane = dock.panes[pane_i-1] - part.button = None - part.orientation = (orientation==wx.HORIZONTAL and \ - [wx.VERTICAL] or [wx.HORIZONTAL])[0] - part.cont_sizer = dock_sizer - part.sizer_item = sizer_item - uiparts.append(part) - - uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only) - - if dock.dock_direction == AUI_DOCK_CENTER or has_maximized_pane: - sizer_item = cont.Add(dock_sizer, 1, wx.EXPAND) - else: - sizer_item = cont.Add(dock_sizer, 0, wx.EXPAND) - - part = AuiDockUIPart() - part.type = AuiDockUIPart.typeDock - part.dock = dock - part.pane = None - part.button = None - part.orientation = orientation - part.cont_sizer = cont - part.sizer_item = sizer_item - uiparts.append(part) - - if dock.IsHorizontal(): - cont.SetItemMinSize(dock_sizer, (0, dock.size)) - else: - cont.SetItemMinSize(dock_sizer, (dock.size, 0)) - - # top and left docks have a sash after them - if not self._has_maximized and not dock.fixed and \ - dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]: - - sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND) - - part = AuiDockUIPart() - part.type = AuiDockUIPart.typeDockSizer - part.dock = dock - part.pane = None - part.button = None - part.orientation = orientation - part.cont_sizer = cont - part.sizer_item = sizer_item - uiparts.append(part) - - return uiparts - - - def LayoutAll(self, panes, docks, uiparts, spacer_only=False, oncheck=True): - """ - Layouts all the UI structures in the interface. - - :param `panes`: a list of :class:`AuiPaneInfo` instances; - :param `docks`: a list of :class:`AuiDockInfo` classes; - :param `uiparts`: a list of UI parts in the interface; - :param bool `spacer_only`: whether to add a simple spacer or a real window; - :param bool `oncheck`: whether to store the results in a class member or not. - """ - container = wx.BoxSizer(wx.VERTICAL) - - pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE) - caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE) - cli_size = self._frame.GetClientSize() - - # empty all docks out - for dock in docks: - dock.panes = [] - if dock.fixed: - # always reset fixed docks' sizes, because - # the contained windows may have been resized - dock.size = 0 - - dock_count = len(docks) - - # iterate through all known panes, filing each - # of them into the appropriate dock. If the - # pane does not exist in the dock, add it - for p in panes: - - # don't layout hidden panes. - if p.IsShown(): - - # find any docks with the same dock direction, dock layer, and - # dock row as the pane we are working on - arr = FindDocks(docks, p.dock_direction, p.dock_layer, p.dock_row) - - if arr: - dock = arr[0] - - else: - # dock was not found, so we need to create a new one - d = AuiDockInfo() - d.dock_direction = p.dock_direction - d.dock_layer = p.dock_layer - d.dock_row = p.dock_row - docks.append(d) - dock = docks[-1] - - if p.HasFlag(p.needsRestore) and not p.HasFlag(p.wasMaximized): - - isHor = dock.IsHorizontal() - sashSize = self._art.GetMetric(AUI_DOCKART_SASH_SIZE) - - # get the sizes of any docks that might - # overlap with our restored dock - - # make list of widths or heights from the size in the dock rects - sizes = [d.rect[2:][isHor] for \ - d in docks if d.IsOk() and \ - (d.IsHorizontal() == isHor) and \ - not d.toolbar and \ - d.dock_direction != AUI_DOCK_CENTER] - - frameRect = GetInternalFrameRect(self._frame, self._docks) - - # set max size allowing for sashes and absolute minimum - maxsize = frameRect[2:][isHor] - sum(sizes) - (len(sizes)*10) - (sashSize*len(sizes)) - dock.size = min(p.previousDockSize,maxsize) - - else: - dock.size = 0 - - if p.HasFlag(p.wasMaximized): - self.MaximizePane(p, savesizes=False) - p.SetFlag(p.wasMaximized, False) - - if p.HasFlag(p.needsRestore): - if p.previousDockPos is not None: - DoInsertPane(dock.panes, dock.dock_direction, dock.dock_layer, dock.dock_row, p.previousDockPos) - p.dock_pos = p.previousDockPos - p.previousDockPos = None - p.SetFlag(p.needsRestore, False) - - if p.IsDocked(): - # remove the pane from any existing docks except this one - docks = RemovePaneFromDocks(docks, p, dock) - - # pane needs to be added to the dock, - # if it doesn't already exist - if not FindPaneInDock(dock, p.window): - dock.panes.append(p) - else: - # remove the pane from any existing docks - docks = RemovePaneFromDocks(docks, p) - - # remove any empty docks - docks = [dock for dock in docks if dock.panes] - - dock_count = len(docks) - # configure the docks further - for ii, dock in enumerate(docks): - # sort the dock pane array by the pane's - # dock position (dock_pos), in ascending order - dock.panes.sort(PaneSortFunc) - dock_pane_count = len(dock.panes) - - # for newly created docks, set up their initial size - if dock.size == 0: - size = 0 - for pane in dock.panes: - pane_size = pane.best_size - if pane_size == wx.Size(-1, -1): - pane_size = pane.min_size - if pane_size == wx.Size(-1, -1) and pane.window: - pane_size = pane.window.GetSize() - if dock.IsHorizontal(): - size = max(pane_size.y, size) - else: - size = max(pane_size.x, size) - - # add space for the border (two times), but only - # if at least one pane inside the dock has a pane border - for pane in dock.panes: - if pane.HasBorder(): - size = size + pane_border_size*2 - break - - # if pane is on the top or bottom, add the caption height, - # but only if at least one pane inside the dock has a caption - if dock.IsHorizontal(): - for pane in dock.panes: - if pane.HasCaption() and not pane.HasCaptionLeft(): - size = size + caption_size - break - else: - for pane in dock.panes: - if pane.HasCaptionLeft() and not pane.HasCaption(): - size = size + caption_size - break - - # new dock's size may not be more than the dock constraint - # parameter specifies. See SetDockSizeConstraint() - max_dock_x_size = int(self._dock_constraint_x*float(cli_size.x)) - max_dock_y_size = int(self._dock_constraint_y*float(cli_size.y)) - if cli_size <= wx.Size(20, 20): - max_dock_x_size = 10000 - max_dock_y_size = 10000 - - if dock.IsHorizontal(): - size = min(size, max_dock_y_size) - else: - size = min(size, max_dock_x_size) - - # absolute minimum size for a dock is 10 pixels - if size < 10: - size = 10 - - dock.size = size - - # determine the dock's minimum size - plus_border = False - plus_caption = False - plus_caption_left = False - dock_min_size = 0 - for pane in dock.panes: - if pane.min_size != wx.Size(-1, -1): - if pane.HasBorder(): - plus_border = True - if pane.HasCaption(): - plus_caption = True - if pane.HasCaptionLeft(): - plus_caption_left = True - if dock.IsHorizontal(): - if pane.min_size.y > dock_min_size: - dock_min_size = pane.min_size.y - else: - if pane.min_size.x > dock_min_size: - dock_min_size = pane.min_size.x - - if plus_border: - dock_min_size += pane_border_size*2 - if plus_caption and dock.IsHorizontal(): - dock_min_size += caption_size - if plus_caption_left and dock.IsVertical(): - dock_min_size += caption_size - - dock.min_size = dock_min_size - - # if the pane's current size is less than it's - # minimum, increase the dock's size to it's minimum - if dock.size < dock.min_size: - dock.size = dock.min_size - - # determine the dock's mode (fixed or proportional) - # determine whether the dock has only toolbars - action_pane_marked = False - dock.fixed = True - dock.toolbar = True - for pane in dock.panes: - if not pane.IsFixed(): - dock.fixed = False - if not pane.IsToolbar(): - dock.toolbar = False - if pane.HasFlag(AuiPaneInfo.optionDockFixed): - dock.fixed = True - if pane.HasFlag(AuiPaneInfo.actionPane): - action_pane_marked = True - - # if the dock mode is proportional and not fixed-pixel, - # reassign the dock_pos to the sequential 0, 1, 2, 3 - # e.g. remove gaps like 1, 2, 30, 500 - if not dock.fixed: - for jj in xrange(dock_pane_count): - pane = dock.panes[jj] - pane.dock_pos = jj - - # if the dock mode is fixed, and none of the panes - # are being moved right now, make sure the panes - # do not overlap each other. If they do, we will - # adjust the panes' positions - if dock.fixed and not action_pane_marked: - pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock) - offset = 0 - for jj in xrange(dock_pane_count): - pane = dock.panes[jj] - pane.dock_pos = pane_positions[jj] - amount = pane.dock_pos - offset - if amount >= 0: - offset += amount - else: - pane.dock_pos += -amount - - offset += pane_sizes[jj] - dock.panes[jj] = pane - - if oncheck: - self._docks[ii] = dock - - # shrink docks if needed -## docks = self.SmartShrink(docks, AUI_DOCK_TOP) -## docks = self.SmartShrink(docks, AUI_DOCK_LEFT) - - if oncheck: - self._docks = docks - - # discover the maximum dock layer - max_layer = 0 - dock_count = len(docks) - - for ii in xrange(dock_count): - max_layer = max(max_layer, docks[ii].dock_layer) - - # clear out uiparts - uiparts = [] - - # create a bunch of box sizers, - # from the innermost level outwards. - cont = None - middle = None - - if oncheck: - docks = self._docks - - for layer in xrange(max_layer+1): - # find any docks in this layer - arr = FindDocks(docks, -1, layer, -1) - # if there aren't any, skip to the next layer - if not arr: - continue - - old_cont = cont - - # create a container which will hold this layer's - # docks (top, bottom, left, right) - cont = wx.BoxSizer(wx.VERTICAL) - - # find any top docks in this layer - arr = FindDocks(docks, AUI_DOCK_TOP, layer, -1) - for row in arr: - uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only) - - # fill out the middle layer (which consists - # of left docks, content area and right docks) - - middle = wx.BoxSizer(wx.HORIZONTAL) - - # find any left docks in this layer - arr = FindDocks(docks, AUI_DOCK_LEFT, layer, -1) - for row in arr: - uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only) - - # add content dock (or previous layer's sizer - # to the middle - if not old_cont: - # find any center docks - arr = FindDocks(docks, AUI_DOCK_CENTER, -1, -1) - if arr: - for row in arr: - uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only) - - elif not self._has_maximized: - # there are no center docks, add a background area - sizer_item = middle.Add((1, 1), 1, wx.EXPAND) - part = AuiDockUIPart() - part.type = AuiDockUIPart.typeBackground - part.pane = None - part.dock = None - part.button = None - part.cont_sizer = middle - part.sizer_item = sizer_item - uiparts.append(part) - else: - middle.Add(old_cont, 1, wx.EXPAND) - - # find any right docks in this layer - arr = FindDocks(docks, AUI_DOCK_RIGHT, layer, -1, reverse=True) - for row in arr: - uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only) - - if len(middle.GetChildren()) > 0: - cont.Add(middle, 1, wx.EXPAND) - - # find any bottom docks in this layer - arr = FindDocks(docks, AUI_DOCK_BOTTOM, layer, -1, reverse=True) - for row in arr: - uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only) - - if not cont: - # no sizer available, because there are no docks, - # therefore we will create a simple background area - cont = wx.BoxSizer(wx.VERTICAL) - sizer_item = cont.Add((1, 1), 1, wx.EXPAND) - part = AuiDockUIPart() - part.type = AuiDockUIPart.typeBackground - part.pane = None - part.dock = None - part.button = None - part.cont_sizer = middle - part.sizer_item = sizer_item - uiparts.append(part) - - if oncheck: - self._uiparts = uiparts - self._docks = docks - - container.Add(cont, 1, wx.EXPAND) - - if oncheck: - return container - else: - return container, panes, docks, uiparts - - - def SetDockSizeConstraint(self, width_pct, height_pct): - """ - When a user creates a new dock by dragging a window into a docked position, - often times the large size of the window will create a dock that is unwieldly - large. - - :class:`AuiManager` by default limits the size of any new dock to 1/3 of the window - size. For horizontal docks, this would be 1/3 of the window height. For vertical - docks, 1/3 of the width. Calling this function will adjust this constraint value. - - The numbers must be between 0.0 and 1.0. For instance, calling :meth:`SetDockSizeConstraint` - with (0.5, 0.5) will cause new docks to be limited to half of the size of the entire - managed window. - - :param float `width_pct`: a number representing the `x` dock size constraint; - :param float `width_pct`: a number representing the `y` dock size constraint. - """ - - self._dock_constraint_x = max(0.0, min(1.0, width_pct)) - self._dock_constraint_y = max(0.0, min(1.0, height_pct)) - - - def GetDockSizeConstraint(self): - """ - Returns the current dock constraint values. - - :see: :meth:`SetDockSizeConstraint` - """ - - return self._dock_constraint_x, self._dock_constraint_y - - - def Update(self): - """ - This method is called after any number of changes are made to any of the - managed panes. :meth:`Update` must be invoked after :meth:`AddPane` - or :meth:`InsertPane` are called in order to "realize" or "commit" the changes. - - In addition, any number of changes may be made to :class:`AuiManager` structures - (retrieved with :meth:`GetPane`), but to realize the changes, :meth:`Update` - must be called. This construction allows pane flicker to be avoided by updating - the whole layout at one time. - """ - self._hover_button = None - self._action_part = None - - # destroy floating panes which have been - # redocked or are becoming non-floating - for p in self._panes: - if p.IsFloating() or not p.frame: - continue - - # because the pane is no longer in a floating, we need to - # reparent it to self._frame and destroy the floating frame - # reduce flicker - p.window.SetSize((1, 1)) - - # the following block is a workaround for bug #1531361 - # (see wxWidgets sourceforge page). On wxGTK (only), when - # a frame is shown/hidden, a move event unfortunately - # also gets fired. Because we may be dragging around - # a pane, we need to cancel that action here to prevent - # a spurious crash. - if self._action_window == p.frame: - if self._frame.HasCapture(): - self._frame.ReleaseMouse() - self._action = actionNone - self._action_window = None - - # hide the frame - if p.frame.IsShown(): - p.frame.Show(False) - - if self._action_window == p.frame: - self._action_window = None - - # reparent to self._frame and destroy the pane - p.window.Reparent(self._frame) - if isinstance(p.window, auibar.AuiToolBar): - p.window.SetAuiManager(self) - - if p.frame: - p.frame.SetSizer(None) - p.frame.Destroy() - p.frame = None - - # Only the master manager should create/destroy notebooks... - if not self._masterManager: - self.UpdateNotebook() - - # delete old sizer first - self._frame.SetSizer(None) - - # create a layout for all of the panes - sizer = self.LayoutAll(self._panes, self._docks, self._uiparts, False) - - # hide or show panes as necessary, - # and float panes as necessary - - pane_count = len(self._panes) - - for ii in xrange(pane_count): - p = self._panes[ii] - pFrame = p.frame - if p.IsFloating(): - if pFrame is None: - # we need to create a frame for this - # pane, which has recently been floated - frame = self.CreateFloatingFrame(self._frame, p) - - # on MSW and Mac, if the owner desires transparent dragging, and - # the dragging is happening right now, then the floating - # window should have this style by default - if self._action in [actionDragFloatingPane, actionDragToolbarPane] and \ - self._agwFlags & AUI_MGR_TRANSPARENT_DRAG: - frame.SetTransparent(150) - - if p.IsToolbar(): - bar = p.window - if isinstance(bar, auibar.AuiToolBar): - bar.SetGripperVisible(False) - agwStyle = bar.GetAGWWindowStyleFlag() - bar.SetAGWWindowStyleFlag(agwStyle & ~AUI_TB_VERTICAL) - bar.Realize() - - s = p.window.GetMinSize() - p.BestSize(s) - p.FloatingSize(wx.DefaultSize) - - frame.SetPaneWindow(p) - p.needsTransparency = True - p.frame = pFrame = frame - if p.IsShown() and not frame.IsShown(): - frame.Show() - frame.Update() - else: - - # frame already exists, make sure it's position - # and size reflect the information in AuiPaneInfo - if pFrame.GetPosition() != p.floating_pos or pFrame.GetSize() != p.floating_size: - pFrame.SetDimensions(p.floating_pos.x, p.floating_pos.y, - p.floating_size.x, p.floating_size.y, wx.SIZE_USE_EXISTING) - - # update whether the pane is resizable or not - style = p.frame.GetWindowStyleFlag() - if p.IsFixed(): - style &= ~wx.RESIZE_BORDER - else: - style |= wx.RESIZE_BORDER - - # update the close button - if p.HasCloseButton(): - style |= wx.CLOSE_BOX - if wx.Platform == '__WXMSW__': - style |= wx.SYSTEM_MENU - else: - style &= ~wx.CLOSE_BOX - if wx.Platform == '__WXMSW__': - style &= ~wx.SYSTEM_MENU - - p.frame.SetWindowStyleFlag(style) - - if pFrame.IsShown() != p.IsShown(): - p.needsTransparency = True - pFrame.Show(p.IsShown()) - - if pFrame.GetTitle() != p.caption: - pFrame.SetTitle(p.caption) - if p.icon.IsOk(): - pFrame.SetIcon(wx.IconFromBitmap(p.icon)) - - else: - - if p.IsToolbar(): - #self.SwitchToolBarOrientation(p) - p.best_size = p.window.GetBestSize() - - if p.window and not p.IsNotebookPage() and p.window.IsShown() != p.IsShown(): - p.window.Show(p.IsShown()) - - if pFrame and p.needsTransparency: - if pFrame.IsShown() and pFrame._transparent != p.transparent: - pFrame.SetTransparent(p.transparent) - pFrame._transparent = p.transparent - - p.needsTransparency = False - - # if "active panes" are no longer allowed, clear - # any optionActive values from the pane states - if self._agwFlags & AUI_MGR_ALLOW_ACTIVE_PANE == 0: - p.state &= ~AuiPaneInfo.optionActive - - self._panes[ii] = p - - old_pane_rects = [] - pane_count = len(self._panes) - - for p in self._panes: - r = wx.Rect() - if p.window and p.IsShown() and p.IsDocked(): - r = p.rect - - old_pane_rects.append(r) - - # apply the new sizer - self._frame.SetSizer(sizer) - self._frame.SetAutoLayout(False) - self.DoFrameLayout() - - # now that the frame layout is done, we need to check - # the new pane rectangles against the old rectangles that - # we saved a few lines above here. If the rectangles have - # changed, the corresponding panes must also be updated - for ii in xrange(pane_count): - p = self._panes[ii] - if p.window and p.IsShown() and p.IsDocked(): - if p.rect != old_pane_rects[ii]: - p.window.Refresh() - p.window.Update() - - if wx.Platform == "__WXMAC__": - self._frame.Refresh() - else: - self.Repaint() - - if not self._masterManager: - e = self.FireEvent(wxEVT_AUI_PERSPECTIVE_CHANGED, None, canVeto=False) - - - def UpdateNotebook(self): - """ Updates the automatic :class:`~lib.agw.aui.auibook.AuiNotebook` in the layout (if any exists). """ - - # Workout how many notebooks we need. - max_notebook = -1 - - # destroy floating panes which have been - # redocked or are becoming non-floating - for paneInfo in self._panes: - if max_notebook < paneInfo.notebook_id: - max_notebook = paneInfo.notebook_id - - # We are the master of our domain - extra_notebook = len(self._notebooks) - max_notebook += 1 - - for i in xrange(extra_notebook, max_notebook): - self.CreateNotebook() - - # Remove pages from notebooks that no-longer belong there ... - for nb, notebook in enumerate(self._notebooks): - pages = notebook.GetPageCount() - pageCounter, allPages = 0, pages - - # Check each tab ... - for page in xrange(pages): - - if page >= allPages: - break - - window = notebook.GetPage(pageCounter) - paneInfo = self.GetPane(window) - if paneInfo.IsOk() and paneInfo.notebook_id != nb: - notebook.RemovePage(pageCounter) - window.Hide() - window.Reparent(self._frame) - pageCounter -= 1 - allPages -= 1 - - pageCounter += 1 - - notebook.DoSizing() - - # Add notebook pages that aren't there already... - for paneInfo in self._panes: - if paneInfo.IsNotebookPage(): - - title = (paneInfo.caption == "" and [paneInfo.name] or [paneInfo.caption])[0] - - notebook = self._notebooks[paneInfo.notebook_id] - page_id = notebook.GetPageIndex(paneInfo.window) - - if page_id < 0: - - paneInfo.window.Reparent(notebook) - notebook.AddPage(paneInfo.window, title, True, paneInfo.icon) - - # Update title and icon ... - else: - - notebook.SetPageText(page_id, title) - notebook.SetPageBitmap(page_id, paneInfo.icon) - - notebook.DoSizing() - - # Wire-up newly created notebooks - elif paneInfo.IsNotebookControl() and not paneInfo.window: - paneInfo.window = self._notebooks[paneInfo.notebook_id] - - # Delete empty notebooks, and convert notebooks with 1 page to - # normal panes... - remap_ids = [-1]*len(self._notebooks) - nb_idx = 0 - - for nb, notebook in enumerate(self._notebooks): - if notebook.GetPageCount() == 1: - - # Convert notebook page to pane... - window = notebook.GetPage(0) - child_pane = self.GetPane(window) - notebook_pane = self.GetPane(notebook) - if child_pane.IsOk() and notebook_pane.IsOk(): - - child_pane.SetDockPos(notebook_pane) - child_pane.window.Hide() - child_pane.window.Reparent(self._frame) - child_pane.frame = None - child_pane.notebook_id = -1 - if notebook_pane.IsFloating(): - child_pane.Float() - - self.DetachPane(notebook) - - notebook.RemovePage(0) - notebook.Destroy() - - else: - - raise Exception("Odd notebook docking") - - elif notebook.GetPageCount() == 0: - - self.DetachPane(notebook) - notebook.Destroy() - - else: - - # Correct page ordering. The original wxPython code - # for this did not work properly, and would misplace - # windows causing errors. - notebook.Freeze() - self._notebooks[nb_idx] = notebook - pages = notebook.GetPageCount() - selected = notebook.GetPage(notebook.GetSelection()) - - # Take each page out of the notebook, group it with - # its current pane, and sort the list by pane.dock_pos - # order - pages_and_panes = [] - for idx in reversed(range(pages)): - page = notebook.GetPage(idx) - pane = self.GetPane(page) - pages_and_panes.append((page, pane)) - notebook.RemovePage(idx) - sorted_pnp = sorted(pages_and_panes, key=lambda tup: tup[1].dock_pos) - - # Grab the attributes from the panes which are ordered - # correctly, and copy those attributes to the original - # panes. (This avoids having to change the ordering - # of self._panes) Then, add the page back into the notebook - sorted_attributes = [self.GetAttributes(tup[1]) - for tup in sorted_pnp] - for attrs, tup in zip(sorted_attributes, pages_and_panes): - pane = tup[1] - self.SetAttributes(pane, attrs) - notebook.AddPage(pane.window, pane.caption) - - notebook.SetSelection(notebook.GetPageIndex(selected), True) - notebook.DoSizing() - notebook.Thaw() - - # It's a keeper. - remap_ids[nb] = nb_idx - nb_idx += 1 - - # Apply remap... - nb_count = len(self._notebooks) - - if nb_count != nb_idx: - - self._notebooks = self._notebooks[0:nb_idx] - for p in self._panes: - if p.notebook_id >= 0: - p.notebook_id = remap_ids[p.notebook_id] - if p.IsNotebookControl(): - p.SetNameFromNotebookId() - - # Make sure buttons are correct ... - for notebook in self._notebooks: - want_max = True - want_min = True - want_close = True - - pages = notebook.GetPageCount() - for page in xrange(pages): - - win = notebook.GetPage(page) - pane = self.GetPane(win) - if pane.IsOk(): - - if not pane.HasCloseButton(): - want_close = False - if not pane.HasMaximizeButton(): - want_max = False - if not pane.HasMinimizeButton(): - want_min = False - - notebook_pane = self.GetPane(notebook) - if notebook_pane.IsOk(): - if notebook_pane.HasMinimizeButton() != want_min: - if want_min: - button = AuiPaneButton(AUI_BUTTON_MINIMIZE) - notebook_pane.state |= AuiPaneInfo.buttonMinimize - notebook_pane.buttons.append(button) - - # todo: remove min/max - - if notebook_pane.HasMaximizeButton() != want_max: - if want_max: - button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE) - notebook_pane.state |= AuiPaneInfo.buttonMaximize - notebook_pane.buttons.append(button) - - # todo: remove min/max - - if notebook_pane.HasCloseButton() != want_close: - if want_close: - button = AuiPaneButton(AUI_BUTTON_CLOSE) - notebook_pane.state |= AuiPaneInfo.buttonClose - notebook_pane.buttons.append(button) - - # todo: remove close - - - def SmartShrink(self, docks, direction): - """ - Used to intelligently shrink the docks' size (if needed). - - :param `docks`: a list of :class:`AuiDockInfo` instances; - :param integer `direction`: the direction in which to shrink. - """ - - sashSize = self._art.GetMetric(AUI_DOCKART_SASH_SIZE) - caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE) - clientSize = self._frame.GetClientSize() - ourDocks = FindDocks(docks, direction, -1, -1) - oppositeDocks = FindOppositeDocks(docks, direction) - oppositeSize = self.GetOppositeDockTotalSize(docks, direction) - ourSize = 0 - - for dock in ourDocks: - ourSize += dock.size - - if not dock.toolbar: - ourSize += sashSize - - shrinkSize = ourSize + oppositeSize - - if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM: - shrinkSize -= clientSize.y - else: - shrinkSize -= clientSize.x - - if shrinkSize <= 0: - return docks - - # Combine arrays - for dock in oppositeDocks: - ourDocks.append(dock) - - oppositeDocks = [] - - for dock in ourDocks: - if dock.toolbar or not dock.resizable: - continue - - dockRange = dock.size - dock.min_size - - if dock.min_size == 0: - dockRange -= sashSize - if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM: - dockRange -= caption_size - - if dockRange >= shrinkSize: - - dock.size -= shrinkSize - return docks - - else: - - dock.size -= dockRange - shrinkSize -= dockRange - - return docks - - - def UpdateDockingGuides(self, paneInfo): - """ - Updates the docking guide windows positions and appearance. - - :param `paneInfo`: a :class:`AuiPaneInfo` instance. - """ - - if len(self._guides) == 0: - self.CreateGuideWindows() - - captionSize = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE) - frameRect = GetInternalFrameRect(self._frame, self._docks) - mousePos = wx.GetMousePosition() - - for indx, guide in enumerate(self._guides): - - pt = wx.Point() - guide_size = guide.host.GetSize() - if not guide.host: - raise Exception("Invalid docking host") - - direction = guide.dock_direction - - if direction == AUI_DOCK_LEFT: - pt.x = frameRect.x + guide_size.x / 2 + 16 - pt.y = frameRect.y + frameRect.height / 2 - - elif direction == AUI_DOCK_TOP: - pt.x = frameRect.x + frameRect.width / 2 - pt.y = frameRect.y + guide_size.y / 2 + 16 - - elif direction == AUI_DOCK_RIGHT: - pt.x = frameRect.x + frameRect.width - guide_size.x / 2 - 16 - pt.y = frameRect.y + frameRect.height / 2 - - elif direction == AUI_DOCK_BOTTOM: - pt.x = frameRect.x + frameRect.width / 2 - pt.y = frameRect.y + frameRect.height - guide_size.y / 2 - 16 - - elif direction == AUI_DOCK_CENTER: - rc = paneInfo.window.GetScreenRect() - pt.x = rc.x + rc.width / 2 - pt.y = rc.y + rc.height / 2 - if paneInfo.HasCaption(): - pt.y -= captionSize / 2 - elif paneInfo.HasCaptionLeft(): - pt.x -= captionSize / 2 - - # guide will be centered around point 'pt' - targetPosition = wx.Point(pt.x - guide_size.x / 2, pt.y - guide_size.y / 2) - - if guide.host.GetPosition() != targetPosition: - guide.host.Move(targetPosition) - - guide.host.AeroMove(targetPosition) - - if guide.dock_direction == AUI_DOCK_CENTER: - guide.host.ValidateNotebookDocking(paneInfo.IsNotebookDockable()) - - guide.host.UpdateDockGuide(mousePos) - - paneInfo.window.Lower() - - - def DoFrameLayout(self): - """ - This is an internal function which invokes :meth:`Sizer.Layout() ` - on the frame's main sizer, then measures all the various UI items - and updates their internal rectangles. - - :note: This should always be called instead of calling - `self._managed_window.Layout()` directly. - """ - - self._frame.Layout() - - for part in self._uiparts: - # get the rectangle of the UI part - # originally, this code looked like this: - # part.rect = wx.Rect(part.sizer_item.GetPosition(), - # part.sizer_item.GetSize()) - # this worked quite well, with one exception: the mdi - # client window had a "deferred" size variable - # that returned the wrong size. It looks like - # a bug in wx, because the former size of the window - # was being returned. So, we will retrieve the part's - # rectangle via other means - - part.rect = part.sizer_item.GetRect() - flag = part.sizer_item.GetFlag() - border = part.sizer_item.GetBorder() - - if flag & wx.TOP: - part.rect.y -= border - part.rect.height += border - if flag & wx.LEFT: - part.rect.x -= border - part.rect.width += border - if flag & wx.BOTTOM: - part.rect.height += border - if flag & wx.RIGHT: - part.rect.width += border - - if part.type == AuiDockUIPart.typeDock: - part.dock.rect = part.rect - if part.type == AuiDockUIPart.typePane: - part.pane.rect = part.rect - - - def GetPanePart(self, wnd): - """ - Looks up the pane border UI part of the - pane specified. This allows the caller to get the exact rectangle - of the pane in question, including decorations like caption and border. - - :param Window `wnd`: the window to which the pane border belongs to. - """ - - for part in self._uiparts: - if part.type == AuiDockUIPart.typePaneBorder and \ - part.pane and part.pane.window == wnd: - return part - - for part in self._uiparts: - if part.type == AuiDockUIPart.typePane and \ - part.pane and part.pane.window == wnd: - return part - - return None - - - def GetDockPixelOffset(self, test): - """ - This is an internal function which returns a dock's offset in pixels from - the left side of the window (for horizontal docks) or from the top of the - window (for vertical docks). - - This value is necessary for calculating fixed-pane/toolbar offsets - when they are dragged. - - :param `test`: a fake :class:`AuiPaneInfo` for testing purposes. - """ - - # the only way to accurately calculate the dock's - # offset is to actually run a theoretical layout - docks, panes = CopyDocksAndPanes2(self._docks, self._panes) - panes.append(test) - - sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False) - client_size = self._frame.GetClientSize() - sizer.SetDimension(0, 0, client_size.x, client_size.y) - sizer.Layout() - - for part in uiparts: - pos = part.sizer_item.GetPosition() - size = part.sizer_item.GetSize() - part.rect = wx.RectPS(pos, size) - if part.type == AuiDockUIPart.typeDock: - part.dock.rect = part.rect - - sizer.Destroy() - - for dock in docks: - if test.dock_direction == dock.dock_direction and \ - test.dock_layer == dock.dock_layer and \ - test.dock_row == dock.dock_row: - - if dock.IsVertical(): - return dock.rect.y - else: - return dock.rect.x - - return 0 - - - def GetPartnerDock(self, dock): - """ - Returns the partner dock for the input dock. - - :param `dock`: a :class:`AuiDockInfo` instance. - """ - - for layer in xrange(dock.dock_layer, -1, -1): - - bestDock = None - - for tmpDock in self._docks: - - if tmpDock.dock_layer != layer: - continue - - if tmpDock.dock_direction != dock.dock_direction: - continue - - if tmpDock.dock_layer < dock.dock_layer: - - if not bestDock or tmpDock.dock_row < bestDock.dock_row: - bestDock = tmpDock - - elif tmpDock.dock_row > dock.dock_row: - - if not bestDock or tmpDock.dock_row > bestDock.dock_row: - bestDock = tmpDock - - if bestDock: - return bestDock - - return None - - - def GetPartnerPane(self, dock, pane): - """ - Returns the partner pane for the input pane. They both need to live - in the same :class:`AuiDockInfo`. - - :param `dock`: a :class:`AuiDockInfo` instance; - :param `pane`: a :class:`AuiPaneInfo` class. - """ - - panePosition = -1 - - for i, tmpPane in enumerate(dock.panes): - if tmpPane.window == pane.window: - panePosition = i - elif not tmpPane.IsFixed() and panePosition != -1: - return tmpPane - - return None - - - def GetTotalPixSizeAndProportion(self, dock): - """ - Returns the dimensions and proportion of the input dock. - - :param `dock`: the :class:`AuiDockInfo` structure to analyze. - """ - - totalPixsize = 0 - totalProportion = 0 - - # determine the total proportion of all resizable panes, - # and the total size of the dock minus the size of all - # the fixed panes - for tmpPane in dock.panes: - - if tmpPane.IsFixed(): - continue - - totalProportion += tmpPane.dock_proportion - - if dock.IsHorizontal(): - totalPixsize += tmpPane.rect.width - else: - totalPixsize += tmpPane.rect.height - -## if tmpPane.min_size.IsFullySpecified(): -## -## if dock.IsHorizontal(): -## totalPixsize -= tmpPane.min_size.x -## else: -## totalPixsize -= tmpPane.min_size.y - - return totalPixsize, totalProportion - - - def GetOppositeDockTotalSize(self, docks, direction): - """ - Returns the dimensions of the dock which lives opposite of the input dock. - - :param `docks`: a list of :class:`AuiDockInfo` structures to analyze; - :param integer `direction`: the direction in which to look for the opposite dock. - """ - - sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE) - caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE) - pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE) - minSizeMax = 0 - result = sash_size - vertical = False - - if direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]: - vertical = True - - # Get minimum size of the most inner area - for tmpDock in docks: - - if tmpDock.dock_layer != 0: - continue - - if tmpDock.dock_direction != AUI_DOCK_CENTER and tmpDock.IsVertical() != vertical: - continue - - for tmpPane in tmpDock.panes: - - minSize = pane_border_size*2 - sash_size - - if vertical: - minSize += tmpPane.min_size.y + caption_size - else: - minSize += tmpPane.min_size.x - - if minSize > minSizeMax: - minSizeMax = minSize - - result += minSizeMax - - # Get opposite docks - oppositeDocks = FindOppositeDocks(docks, direction) - - # Sum size of the opposite docks and their sashes - for dock in oppositeDocks: - result += dock.size - # if it's not a toolbar add the sash_size too - if not dock.toolbar: - result += sash_size - - return result - - - def CalculateDockSizerLimits(self, dock): - """ - Calculates the minimum and maximum sizes allowed for the input dock. - - :param `dock`: the :class:`AuiDockInfo` structure to analyze. - """ - - docks, panes = CopyDocksAndPanes2(self._docks, self._panes) - - sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE) - caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE) - opposite_size = self.GetOppositeDockTotalSize(docks, dock.dock_direction) - - for tmpDock in docks: - - if tmpDock.dock_direction == dock.dock_direction and \ - tmpDock.dock_layer == dock.dock_layer and \ - tmpDock.dock_row == dock.dock_row: - - tmpDock.size = 1 - break - - sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False) - client_size = self._frame.GetClientSize() - sizer.SetDimension(0, 0, client_size.x, client_size.y) - sizer.Layout() - - for part in uiparts: - - part.rect = wx.RectPS(part.sizer_item.GetPosition(), part.sizer_item.GetSize()) - if part.type == AuiDockUIPart.typeDock: - part.dock.rect = part.rect - - sizer.Destroy() - new_dock = None - - for tmpDock in docks: - if tmpDock.dock_direction == dock.dock_direction and \ - tmpDock.dock_layer == dock.dock_layer and \ - tmpDock.dock_row == dock.dock_row: - - new_dock = tmpDock - break - - partnerDock = self.GetPartnerDock(dock) - - if partnerDock: - partnerRange = partnerDock.size - partnerDock.min_size - if partnerDock.min_size == 0: - partnerRange -= sash_size - if dock.IsHorizontal(): - partnerRange -= caption_size - - direction = dock.dock_direction - - if direction == AUI_DOCK_LEFT: - minPix = new_dock.rect.x + new_dock.rect.width - maxPix = dock.rect.x + dock.rect.width - maxPix += partnerRange - - elif direction == AUI_DOCK_TOP: - minPix = new_dock.rect.y + new_dock.rect.height - maxPix = dock.rect.y + dock.rect.height - maxPix += partnerRange - - elif direction == AUI_DOCK_RIGHT: - minPix = dock.rect.x - partnerRange - sash_size - maxPix = new_dock.rect.x - sash_size - - elif direction == AUI_DOCK_BOTTOM: - minPix = dock.rect.y - partnerRange - sash_size - maxPix = new_dock.rect.y - sash_size - - return minPix, maxPix - - direction = new_dock.dock_direction - - if direction == AUI_DOCK_LEFT: - minPix = new_dock.rect.x + new_dock.rect.width - maxPix = client_size.x - opposite_size - sash_size - - elif direction == AUI_DOCK_TOP: - minPix = new_dock.rect.y + new_dock.rect.height - maxPix = client_size.y - opposite_size - sash_size - - elif direction == AUI_DOCK_RIGHT: - minPix = opposite_size - maxPix = new_dock.rect.x - sash_size - - elif direction == AUI_DOCK_BOTTOM: - minPix = opposite_size - maxPix = new_dock.rect.y - sash_size - - return minPix, maxPix - - - def CalculatePaneSizerLimits(self, dock, pane): - """ - Calculates the minimum and maximum sizes allowed for the input pane. - - :param `dock`: the :class:`AuiDockInfo` structure to which `pane` belongs to; - :param `pane`: a :class:`AuiPaneInfo` class for which calculation are requested. - """ - - if pane.IsFixed(): - if dock.IsHorizontal(): - minPix = maxPix = pane.rect.x + 1 + pane.rect.width - else: - minPix = maxPix = pane.rect.y + 1 + pane.rect.height - - return minPix, maxPix - - totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock) - partnerPane = self.GetPartnerPane(dock, pane) - - if dock.IsHorizontal(): - - minPix = pane.rect.x + 1 - maxPix = pane.rect.x + 1 + pane.rect.width - - if pane.min_size.IsFullySpecified(): - minPix += pane.min_size.x - else: - minPix += 1 - - if partnerPane: - maxPix += partnerPane.rect.width - - if partnerPane.min_size.IsFullySpecified(): - maxPix -= partnerPane.min_size.x - 1 - - else: - minPix = maxPix - - else: - - minPix = pane.rect.y + 1 - maxPix = pane.rect.y + 1 + pane.rect.height - - if pane.min_size.IsFullySpecified(): - minPix += pane.min_size.y - else: - minPix += 1 - - if partnerPane: - maxPix += partnerPane.rect.height - - if partnerPane.min_size.IsFullySpecified(): - maxPix -= partnerPane.min_size.y - 1 - - else: - minPix = maxPix - - return minPix, maxPix - - - def CheckMovableSizer(self, part): - """ - Checks if a UI part can be actually resized. - - :param AuiDockUIPart `part`: a UI part. - """ - - # a dock may not be resized if it has a single - # pane which is not resizable - if part.type == AuiDockUIPart.typeDockSizer and part.dock and \ - len(part.dock.panes) == 1 and part.dock.panes[0].IsFixed(): - - return False - - if part.pane: - - # panes that may not be resized should be ignored here - minPix, maxPix = self.CalculatePaneSizerLimits(part.dock, part.pane) - - if minPix == maxPix: - return False - - return True - - - def PaneFromTabEvent(self, event): - """ - Returns a :class:`AuiPaneInfo` from a :class:`~lib.agw.aui.auibook.AuiNotebook` event. - - :param `event`: a :class:`~lib.agw.aui.auibook.AuiNotebookEvent` event. - """ - - obj = event.GetEventObject() - - if obj and isinstance(obj, auibook.AuiTabCtrl): - - page_idx = obj.GetActivePage() - - if page_idx >= 0: - page = obj.GetPage(page_idx) - window = page.window - if window: - return self.GetPane(window) - - elif obj and isinstance(obj, auibook.AuiNotebook): - - page_idx = event.GetSelection() - - if page_idx >= 0: - window = obj.GetPage(page_idx) - if window: - return self.GetPane(window) - - return NonePaneInfo - - - def OnTabBeginDrag(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_BEGIN_DRAG`` event. - - :param `event`: a :class:`~lib.agw.aui.auibook.AuiNotebookEvent` event to be processed. - """ - - if self._masterManager: - self._masterManager.OnTabBeginDrag(event) - - else: - paneInfo = self.PaneFromTabEvent(event) - - if paneInfo.IsOk(): - - # It's one of ours! - self._action = actionDragFloatingPane - mouse = wx.GetMousePosition() - - # set initial float position - may have to think about this - # offset a bit more later ... - self._action_offset = wx.Point(20, 10) - self._toolbar_action_offset = wx.Point(20, 10) - - paneInfo.floating_pos = mouse - self._action_offset - paneInfo.dock_pos = AUI_DOCK_NONE - paneInfo.notebook_id = -1 - - tab = event.GetEventObject() - - if tab.HasCapture(): - tab.ReleaseMouse() - - # float the window - if paneInfo.IsMaximized(): - self.RestorePane(paneInfo) - paneInfo.Float() - self.Update() - - self._action_window = paneInfo.window - - self._frame.CaptureMouse() - event.SetDispatched(True) - - else: - - # not our window - event.Skip() - - - def OnTabPageClose(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_PAGE_CLOSE`` event. - - :param `event`: a :class:`~lib.agw.aui.auibook.AuiNotebookEvent` event to be processed. - """ - - if self._masterManager: - self._masterManager.OnTabPageClose(event) - - else: - - p = self.PaneFromTabEvent(event) - if p.IsOk(): - - # veto it because we will call "RemovePage" ourselves - event.Veto() - - # Now ask the app if they really want to close... - # fire pane close event - e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE) - e.SetPane(p) - e.SetCanVeto(True) - self.ProcessMgrEvent(e) - - if e.GetVeto(): - return - - self.ClosePane(p) - self.Update() - else: - event.Skip() - - - def OnTabSelected(self, event): - """ - Handles the ``EVT_AUINOTEBOOK_PAGE_CHANGED`` event. - - :param `event`: a :class:`~lib.agw.aui.auibook.AuiNotebookEvent` event to be processed. - """ - - if self._masterManager: - self._masterManager.OnTabSelected(event) - return - - obj = event.GetEventObject() - - if obj and isinstance(obj, auibook.AuiNotebook): - - notebook = obj - page = notebook.GetPage(event.GetSelection()) - paneInfo = self.GetPane(page) - - if paneInfo.IsOk(): - notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id) - if notebookRoot: - - notebookRoot.Caption(paneInfo.caption) - self.RefreshCaptions() - - event.Skip() - - - def GetNotebooks(self): - """ Returns all the automatic :class:`~lib.agw.aui.auibook.AuiNotebook` in the :class:`AuiManager`. """ - - if self._masterManager: - return self._masterManager.GetNotebooks() - - return self._notebooks - - - def SetMasterManager(self, manager): - """ - Sets the master manager for an automatic :class:`~lib.agw.aui.auibook.AuiNotebook`. - - :param `manager`: an instance of :class:`AuiManager`. - """ - - self._masterManager = manager - - - def ProcessDockResult(self, target, new_pos): - """ - This is a utility function used by :meth:`DoDrop` - it checks - if a dock operation is allowed, the new dock position is copied into - the target info. If the operation was allowed, the function returns ``True``. - - :param `target`: the :class:`AuiPaneInfo` instance to be docked; - :param integer `new_pos`: the new docking position if the docking operation is allowed. - """ - - allowed = False - direction = new_pos.dock_direction - - if direction == AUI_DOCK_TOP: - allowed = target.IsTopDockable() - elif direction == AUI_DOCK_BOTTOM: - allowed = target.IsBottomDockable() - elif direction == AUI_DOCK_LEFT: - allowed = target.IsLeftDockable() - elif direction == AUI_DOCK_RIGHT: - allowed = target.IsRightDockable() - - if allowed: - target = new_pos - - if target.IsToolbar(): - self.SwitchToolBarOrientation(target) - - return allowed, target - - - def SwitchToolBarOrientation(self, pane): - """ - Switches the toolbar orientation from vertical to horizontal and vice-versa. - This is especially useful for vertical docked toolbars once they float. - - :param `pane`: an instance of :class:`AuiPaneInfo`, which may have a :class:`~lib.agw.aui.auibar.AuiToolBar` - window associated with it. - """ - if not isinstance(pane.window, auibar.AuiToolBar): - return pane - - if pane.IsFloating(): - return pane - - toolBar = pane.window - direction = pane.dock_direction - vertical = direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT] - - agwStyle = toolBar.GetAGWWindowStyleFlag() - new_agwStyle = agwStyle - - if vertical: - new_agwStyle |= AUI_TB_VERTICAL - else: - new_agwStyle &= ~(AUI_TB_VERTICAL) - - if agwStyle != new_agwStyle: - toolBar.SetAGWWindowStyleFlag(new_agwStyle) - if not toolBar.GetGripperVisible(): - toolBar.SetGripperVisible(True) - - s = pane.window.GetMinSize() - pane.BestSize(s) - if new_agwStyle != agwStyle: - toolBar.Realize() - - return pane - - - def DoDrop(self, docks, panes, target, pt, offset=wx.Point(0, 0)): - """ - This is an important function. It basically takes a mouse position, - and determines where the panes new position would be. If the pane is to be - dropped, it performs the drop operation using the specified dock and pane - arrays. By specifying copy dock and pane arrays when calling, a "what-if" - scenario can be performed, giving precise coordinates for drop hints. - - :param `docks`: a list of :class:`AuiDockInfo` classes; - :param `panes`: a list of :class:`AuiPaneInfo` instances; - :param Point `pt`: a mouse position to check for a drop operation; - :param Point `offset`: a possible offset from the input point `pt`. - """ - - if target.IsToolbar(): - return self.DoDropToolbar(docks, panes, target, pt, offset) - elif target.IsFloating(): - return self.DoDropFloatingPane(docks, panes, target, pt) - else: - return self.DoDropNonFloatingPane(docks, panes, target, pt) - - - def CopyTarget(self, target): - """ - Copies all the attributes of the input `target` into another :class:`AuiPaneInfo`. - - :param `target`: the source :class:`AuiPaneInfo` from where to copy attributes. - """ - - drop = AuiPaneInfo() - drop.name = target.name - drop.caption = target.caption - drop.window = target.window - drop.frame = target.frame - drop.state = target.state - drop.dock_direction = target.dock_direction - drop.dock_layer = target.dock_layer - drop.dock_row = target.dock_row - drop.dock_pos = target.dock_pos - drop.best_size = wx.Size(*target.best_size) - drop.min_size = wx.Size(*target.min_size) - drop.max_size = wx.Size(*target.max_size) - drop.floating_pos = wx.Point(*target.floating_pos) - drop.floating_size = wx.Size(*target.floating_size) - drop.dock_proportion = target.dock_proportion - drop.buttons = target.buttons - drop.rect = wx.Rect(*target.rect) - drop.icon = target.icon - drop.notebook_id = target.notebook_id - drop.transparent = target.transparent - drop.snapped = target.snapped - drop.minimize_mode = target.minimize_mode - drop.minimize_target = target.minimize_target - - return drop - - - def DoDropToolbar(self, docks, panes, target, pt, offset): - """ - Handles the situation in which the dropped pane contains a toolbar. - - :param `docks`: a list of :class:`AuiDockInfo` classes; - :param `panes`: a list of :class:`AuiPaneInfo` instances; - :param AuiPaneInfo `target`: the target pane containing the toolbar; - :param Point `pt`: a mouse position to check for a drop operation; - :param Point `offset`: a possible offset from the input point `pt`. - """ - - drop = self.CopyTarget(target) - - # The result should always be shown - drop.Show() - - # Check to see if the toolbar has been dragged out of the window - if CheckOutOfWindow(self._frame, pt): - if self._agwFlags & AUI_MGR_ALLOW_FLOATING and drop.IsFloatable(): - drop.Float() - - return self.ProcessDockResult(target, drop) - - # Allow directional change when the cursor leaves this rect - safeRect = wx.Rect(*target.rect) - if target.IsHorizontal(): - safeRect.Inflate(100, 50) - else: - safeRect.Inflate(50, 100) - - # Check to see if the toolbar has been dragged to edge of the frame - dropDir = CheckEdgeDrop(self._frame, docks, pt) - - if dropDir != -1: - - if dropDir == wx.LEFT: - drop.Dock().Left().Layer(auiToolBarLayer).Row(0). \ - Position(pt.y - self.GetDockPixelOffset(drop) - offset.y) - - elif dropDir == wx.RIGHT: - drop.Dock().Right().Layer(auiToolBarLayer).Row(0). \ - Position(pt.y - self.GetDockPixelOffset(drop) - offset.y) - - elif dropDir == wx.TOP: - drop.Dock().Top().Layer(auiToolBarLayer).Row(0). \ - Position(pt.x - self.GetDockPixelOffset(drop) - offset.x) - - elif dropDir == wx.BOTTOM: - drop.Dock().Bottom().Layer(auiToolBarLayer).Row(0). \ - Position(pt.x - self.GetDockPixelOffset(drop) - offset.x) - - if not target.IsFloating() and safeRect.Contains(pt) and \ - target.dock_direction != drop.dock_direction: - return False, target - - return self.ProcessDockResult(target, drop) - - # If the windows is floating and out of the client area, do nothing - if drop.IsFloating() and not self._frame.GetClientRect().Contains(pt): - return False, target - - # Ok, can't drop on edge - check internals ... - - clientSize = self._frame.GetClientSize() - x = Clip(pt.x, 0, clientSize.x - 1) - y = Clip(pt.y, 0, clientSize.y - 1) - part = self.HitTest(x, y) - - if not part or not part.dock: - return False, target - - dock = part.dock - - # toolbars may only be moved in and to fixed-pane docks, - # otherwise we will try to float the pane. Also, the pane - # should float if being dragged over center pane windows - if not dock.fixed or dock.dock_direction == AUI_DOCK_CENTER: - - if (self._agwFlags & AUI_MGR_ALLOW_FLOATING and drop.IsFloatable()) or \ - dock.dock_direction not in [AUI_DOCK_CENTER, AUI_DOCK_NONE]: - if drop.IsFloatable(): - drop.Float() - - return self.ProcessDockResult(target, drop) - - # calculate the offset from where the dock begins - # to the point where the user dropped the pane - dockDropOffset = 0 - if dock.IsHorizontal(): - dockDropOffset = pt.x - dock.rect.x - offset.x - else: - dockDropOffset = pt.y - dock.rect.y - offset.y - - drop.Dock().Direction(dock.dock_direction).Layer(dock.dock_layer). \ - Row(dock.dock_row).Position(dockDropOffset) - - if (pt.y <= dock.rect.GetTop() + 2 and dock.IsHorizontal()) or \ - (pt.x <= dock.rect.GetLeft() + 2 and dock.IsVertical()): - - if dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]: - row = drop.dock_row - panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row) - drop.dock_row = row - - else: - panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row+1) - drop.dock_row = dock.dock_row + 1 - - if (pt.y >= dock.rect.GetBottom() - 2 and dock.IsHorizontal()) or \ - (pt.x >= dock.rect.GetRight() - 2 and dock.IsVertical()): - - if dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]: - panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row+1) - drop.dock_row = dock.dock_row+1 - - else: - row = drop.dock_row - panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row) - drop.dock_row = row - - if not target.IsFloating() and safeRect.Contains(pt) and \ - target.dock_direction != drop.dock_direction: - return False, target - - return self.ProcessDockResult(target, drop) - - - def DoDropFloatingPane(self, docks, panes, target, pt): - """ - Handles the situation in which the dropped pane contains a normal window. - - :param `docks`: a list of :class:`AuiDockInfo` classes; - :param `panes`: a list of :class:`AuiPaneInfo` instances; - :param AuiPaneInfo `target`: the target pane containing the window; - :param Point `pt`: a mouse position to check for a drop operation. - """ - screenPt = self._frame.ClientToScreen(pt) - paneInfo = self.PaneHitTest(panes, pt) - - if paneInfo.IsMaximized(): - return False, target - - if paneInfo.window is None: - return False, target - - # search the dock guides. - # reverse order to handle the center first. - for i in xrange(len(self._guides)-1, -1, -1): - guide = self._guides[i] - - # do hit testing on the guide - dir = guide.host.HitTest(screenPt.x, screenPt.y) - - if dir == -1: # point was outside of the dock guide - continue - - if dir == wx.ALL: # target is a single dock guide - return self.DoDropLayer(docks, target, guide.dock_direction) - - elif dir == wx.CENTER: - - if not target.IsNotebookDockable(): - continue - if not paneInfo.IsNotebookDockable() and not paneInfo.IsNotebookControl(): - continue - - if not paneInfo.HasNotebook(): - - # Add a new notebook pane with the original as a tab... - self.CreateNotebookBase(panes, paneInfo) - - # Add new item to notebook - target.NotebookPage(paneInfo.notebook_id) - - else: - - drop_pane = False - drop_row = False - - insert_dir = paneInfo.dock_direction - insert_layer = paneInfo.dock_layer - insert_row = paneInfo.dock_row - insert_pos = paneInfo.dock_pos - - if insert_dir == AUI_DOCK_CENTER: - - insert_layer = 0 - if dir == wx.LEFT: - insert_dir = AUI_DOCK_LEFT - elif dir == wx.UP: - insert_dir = AUI_DOCK_TOP - elif dir == wx.RIGHT: - insert_dir = AUI_DOCK_RIGHT - elif dir == wx.DOWN: - insert_dir = AUI_DOCK_BOTTOM - - if insert_dir == AUI_DOCK_LEFT: - - drop_pane = (dir == wx.UP or dir == wx.DOWN) - drop_row = (dir == wx.LEFT or dir == wx.RIGHT) - if dir == wx.RIGHT: - insert_row += 1 - elif dir == wx.DOWN: - insert_pos += 1 - - elif insert_dir == AUI_DOCK_RIGHT: - - drop_pane = (dir == wx.UP or dir == wx.DOWN) - drop_row = (dir == wx.LEFT or dir == wx.RIGHT) - if dir == wx.LEFT: - insert_row += 1 - elif dir == wx.DOWN: - insert_pos += 1 - - elif insert_dir == AUI_DOCK_TOP: - - drop_pane = (dir == wx.LEFT or dir == wx.RIGHT) - drop_row = (dir == wx.UP or dir == wx.DOWN) - if dir == wx.DOWN: - insert_row += 1 - elif dir == wx.RIGHT: - insert_pos += 1 - - elif insert_dir == AUI_DOCK_BOTTOM: - - drop_pane = (dir == wx.LEFT or dir == wx.RIGHT) - drop_row = (dir == wx.UP or dir == wx.DOWN) - if dir == wx.UP: - insert_row += 1 - elif dir == wx.RIGHT: - insert_pos += 1 - - if paneInfo.dock_direction == AUI_DOCK_CENTER: - insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1 - - if drop_pane: - return self.DoDropPane(panes, target, insert_dir, insert_layer, insert_row, insert_pos) - - if drop_row: - return self.DoDropRow(panes, target, insert_dir, insert_layer, insert_row) - - return True, target - - return False, target - - - def DoDropNonFloatingPane(self, docks, panes, target, pt): - """ - Handles the situation in which the dropped pane is not floating. - - :param `docks`: a list of :class:`AuiDockInfo` classes; - :param `panes`: a list of :class:`AuiPaneInfo` instances; - :param AuiPaneInfo `target`: the target pane containing the toolbar; - :param Point `pt`: a mouse position to check for a drop operation. - """ - - screenPt = self._frame.ClientToScreen(pt) - clientSize = self._frame.GetClientSize() - frameRect = GetInternalFrameRect(self._frame, self._docks) - - drop = self.CopyTarget(target) - - # The result should always be shown - drop.Show() - - part = self.HitTest(pt.x, pt.y) - - if not part: - return False, target - - if part.type == AuiDockUIPart.typeDockSizer: - - if len(part.dock.panes) != 1: - return False, target - - part = self.GetPanePart(part.dock.panes[0].window) - if not part: - return False, target - - if not part.pane: - return False, target - - part = self.GetPanePart(part.pane.window) - if not part: - return False, target - - insert_dock_row = False - insert_row = part.pane.dock_row - insert_dir = part.pane.dock_direction - insert_layer = part.pane.dock_layer - - direction = part.pane.dock_direction - - if direction == AUI_DOCK_TOP: - if pt.y >= part.rect.y and pt.y < part.rect.y+auiInsertRowPixels: - insert_dock_row = True - - elif direction == AUI_DOCK_BOTTOM: - if pt.y > part.rect.y+part.rect.height-auiInsertRowPixels and \ - pt.y <= part.rect.y + part.rect.height: - insert_dock_row = True - - elif direction == AUI_DOCK_LEFT: - if pt.x >= part.rect.x and pt.x < part.rect.x+auiInsertRowPixels: - insert_dock_row = True - - elif direction == AUI_DOCK_RIGHT: - if pt.x > part.rect.x+part.rect.width-auiInsertRowPixels and \ - pt.x <= part.rect.x+part.rect.width: - insert_dock_row = True - - elif direction == AUI_DOCK_CENTER: - - # "new row pixels" will be set to the default, but - # must never exceed 20% of the window size - new_row_pixels_x = auiNewRowPixels - new_row_pixels_y = auiNewRowPixels - - if new_row_pixels_x > (part.rect.width*20)/100: - new_row_pixels_x = (part.rect.width*20)/100 - - if new_row_pixels_y > (part.rect.height*20)/100: - new_row_pixels_y = (part.rect.height*20)/100 - - # determine if the mouse pointer is in a location that - # will cause a new row to be inserted. The hot spot positions - # are along the borders of the center pane - - insert_layer = 0 - insert_dock_row = True - pr = part.rect - - if pt.x >= pr.x and pt.x < pr.x + new_row_pixels_x: - insert_dir = AUI_DOCK_LEFT - elif pt.y >= pr.y and pt.y < pr.y + new_row_pixels_y: - insert_dir = AUI_DOCK_TOP - elif pt.x >= pr.x + pr.width - new_row_pixels_x and pt.x < pr.x + pr.width: - insert_dir = AUI_DOCK_RIGHT - elif pt.y >= pr.y+ pr.height - new_row_pixels_y and pt.y < pr.y + pr.height: - insert_dir = AUI_DOCK_BOTTOM - else: - return False, target - - insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1 - - if insert_dock_row: - - panes = DoInsertDockRow(panes, insert_dir, insert_layer, insert_row) - drop.Dock().Direction(insert_dir).Layer(insert_layer). \ - Row(insert_row).Position(0) - - return self.ProcessDockResult(target, drop) - - # determine the mouse offset and the pane size, both in the - # direction of the dock itself, and perpendicular to the dock - - if part.orientation == wx.VERTICAL: - - offset = pt.y - part.rect.y - size = part.rect.GetHeight() - - else: - - offset = pt.x - part.rect.x - size = part.rect.GetWidth() - - drop_position = part.pane.dock_pos - - # if we are in the top/left part of the pane, - # insert the pane before the pane being hovered over - if offset <= size/2: - - drop_position = part.pane.dock_pos - panes = DoInsertPane(panes, - part.pane.dock_direction, - part.pane.dock_layer, - part.pane.dock_row, - part.pane.dock_pos) - - # if we are in the bottom/right part of the pane, - # insert the pane before the pane being hovered over - if offset > size/2: - - drop_position = part.pane.dock_pos+1 - panes = DoInsertPane(panes, - part.pane.dock_direction, - part.pane.dock_layer, - part.pane.dock_row, - part.pane.dock_pos+1) - - - drop.Dock(). \ - Direction(part.dock.dock_direction). \ - Layer(part.dock.dock_layer).Row(part.dock.dock_row). \ - Position(drop_position) - - return self.ProcessDockResult(target, drop) - - - def DoDropLayer(self, docks, target, dock_direction): - """ - Handles the situation in which `target` is a single dock guide. - - :param `docks`: a list of :class:`AuiDockInfo` classes; - :param AuiPaneInfo `target`: the target pane; - :param integer `dock_direction`: the docking direction. - """ - - drop = self.CopyTarget(target) - - if dock_direction == AUI_DOCK_LEFT: - drop.Dock().Left() - drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_LEFT), - GetMaxLayer(docks, AUI_DOCK_BOTTOM)), - GetMaxLayer(docks, AUI_DOCK_TOP)) + 1 - - elif dock_direction == AUI_DOCK_TOP: - drop.Dock().Top() - drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_TOP), - GetMaxLayer(docks, AUI_DOCK_LEFT)), - GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1 - - elif dock_direction == AUI_DOCK_RIGHT: - drop.Dock().Right() - drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_RIGHT), - GetMaxLayer(docks, AUI_DOCK_TOP)), - GetMaxLayer(docks, AUI_DOCK_BOTTOM)) + 1 - - elif dock_direction == AUI_DOCK_BOTTOM: - drop.Dock().Bottom() - drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_BOTTOM), - GetMaxLayer(docks, AUI_DOCK_LEFT)), - GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1 - - else: - return False, target - - - drop.Dock().Layer(drop_new_layer) - return self.ProcessDockResult(target, drop) - - - def DoDropPane(self, panes, target, dock_direction, dock_layer, dock_row, dock_pos): - """ - Drop a pane in the interface. - - :param `panes`: a list of :class:`AuiPaneInfo` classes; - :param AuiPaneInfo `target`: the target pane; - :param integer `dock_direction`: the docking direction; - :param integer `dock_layer`: the docking layer; - :param integer `dock_row`: the docking row; - :param integer `dock_pos`: the docking position. - """ - - drop = self.CopyTarget(target) - panes = DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos) - - drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(dock_pos) - return self.ProcessDockResult(target, drop) - - - def DoDropRow(self, panes, target, dock_direction, dock_layer, dock_row): - """ - Insert a row in the interface before dropping. - - :param `panes`: a list of :class:`AuiPaneInfo` classes; - :param AuiPaneInfo `target`: the target pane; - :param integer `dock_direction`: the docking direction; - :param integer `dock_layer`: the docking layer; - :param integer `dock_row`: the docking row. - """ - - drop = self.CopyTarget(target) - panes = DoInsertDockRow(panes, dock_direction, dock_layer, dock_row) - - drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(0) - return self.ProcessDockResult(target, drop) - - - def ShowHint(self, rect): - """ - Shows the AUI hint window. - - :param Rect `rect`: the hint rect calculated in advance. - """ - - if rect == self._last_hint: - return - - if self._agwFlags & AUI_MGR_RECTANGLE_HINT and wx.Platform != "__WXMAC__": - - if self._last_hint != rect: - # remove the last hint rectangle - self._last_hint = wx.Rect(*rect) - self._frame.Refresh() - self._frame.Update() - - screendc = wx.ScreenDC() - clip = wx.Region(1, 1, 10000, 10000) - - # clip all floating windows, so we don't draw over them - for pane in self._panes: - if pane.IsFloating() and pane.frame.IsShown(): - - rect2 = wx.Rect(*pane.frame.GetRect()) - if wx.Platform == "__WXGTK__": - # wxGTK returns the client size, not the whole frame size - rect2.width += 15 - rect2.height += 35 - rect2.Inflate(5, 5) - - clip.SubtractRect(rect2) - - # As we can only hide the hint by redrawing the managed window, we - # need to clip the region to the managed window too or we get - # nasty redrawn problems. - clip.IntersectRect(self._frame.GetRect()) - screendc.SetClippingRegionAsRegion(clip) - - stipple = PaneCreateStippleBitmap() - brush = wx.BrushFromBitmap(stipple) - screendc.SetBrush(brush) - screendc.SetPen(wx.TRANSPARENT_PEN) - screendc.DrawRectangle(rect.x, rect.y, 5, rect.height) - screendc.DrawRectangle(rect.x+5, rect.y, rect.width-10, 5) - screendc.DrawRectangle(rect.x+rect.width-5, rect.y, 5, rect.height) - screendc.DrawRectangle(rect.x+5, rect.y+rect.height-5, rect.width-10, 5) - RefreshDockingGuides(self._guides) - - return - - if not self._hint_window: - self.CreateHintWindow() - - if self._hint_window: - self._hint_window.SetRect(rect) - self._hint_window.Show() - - self._hint_fadeamt = self._hint_fademax - - if self._agwFlags & AUI_MGR_HINT_FADE: - self._hint_fadeamt = 0 - self._hint_window.SetTransparent(self._hint_fadeamt) - - if self._action == actionDragFloatingPane and self._action_window: - self._action_window.SetFocus() - - if self._hint_fadeamt != self._hint_fademax: # Only fade if we need to - # start fade in timer - self._hint_fadetimer.Start(5) - - self._last_hint = wx.Rect(*rect) - - - def HideHint(self): - """ Hides a transparent window hint if there is one. """ - - # hides a transparent window hint if there is one - if self._hint_window: - self._hint_window.Hide() - - self._hint_fadetimer.Stop() - self._last_hint = wx.Rect() - - - def IsPaneButtonVisible(self, part): - """ - Returns whether a pane button in the pane caption is visible. - - :param AuiDockUIPart `part`: the UI part to analyze. - """ - - captionRect = wx.Rect() - - for temp_part in self._uiparts: - if temp_part.pane == part.pane and \ - temp_part.type == AuiDockUIPart.typeCaption: - captionRect = temp_part.rect - break - - return captionRect.ContainsRect(part.rect) - - - def DrawPaneButton(self, dc, part, pt): - """ - Draws a pane button in the caption (convenience function). - - :param `dc`: a :class:`DC` device context object; - :param AuiDockUIPart `part`: the UI part to analyze; - :param Point `pt`: the mouse location. - """ - - if not self.IsPaneButtonVisible(part): - return - - state = AUI_BUTTON_STATE_NORMAL - - if part.rect.Contains(pt): - - if _VERSION_STRING < "2.9": - leftDown = wx.GetMouseState().LeftDown() - else: - leftDown = wx.GetMouseState().LeftIsDown() - - if leftDown: - state = AUI_BUTTON_STATE_PRESSED - else: - state = AUI_BUTTON_STATE_HOVER - - self._art.DrawPaneButton(dc, self._frame, part.button.button_id, - state, part.rect, part.pane) - - - def RefreshButton(self, part): - """ - Refreshes a pane button in the caption. - - :param AuiDockUIPart `part`: the UI part to analyze. - """ - - rect = wx.Rect(*part.rect) - rect.Inflate(2, 2) - self._frame.Refresh(True, rect) - self._frame.Update() - - - def RefreshCaptions(self): - """ Refreshes all pane captions. """ - - for part in self._uiparts: - if part.type == AuiDockUIPart.typeCaption: - self._frame.Refresh(True, part.rect) - self._frame.Update() - - - def CalculateHintRect(self, pane_window, pt, offset): - """ - Calculates the drop hint rectangle. - - The method first calls :meth:`DoDrop` to determine the exact position the pane would - be at were if dropped. If the pane would indeed become docked at the - specified drop point, the the rectangle hint will be returned in - screen coordinates. Otherwise, an empty rectangle is returned. - - :param Window `pane_window`: it is the window pointer of the pane being dragged; - :param Point `pt`: is the mouse position, in client coordinates; - :param Point `offset`: describes the offset that the mouse is from the upper-left - corner of the item being dragged. - """ - - # we need to paint a hint rectangle to find out the exact hint rectangle, - # we will create a new temporary layout and then measure the resulting - # rectangle we will create a copy of the docking structures (self._docks) - # so that we don't modify the real thing on screen - - rect = wx.Rect() - pane = self.GetPane(pane_window) - - attrs = self.GetAttributes(pane) - hint = AuiPaneInfo() - hint = self.SetAttributes(hint, attrs) - - if hint.name != "__HINT__": - self._oldname = hint.name - - hint.name = "__HINT__" - hint.PaneBorder(True) - hint.Show() - - if not hint.IsOk(): - hint.name = self._oldname - return rect - - docks, panes = CopyDocksAndPanes2(self._docks, self._panes) - - # remove any pane already there which bears the same window - # this happens when you are moving a pane around in a dock - for ii in xrange(len(panes)): - if panes[ii].window == pane_window: - docks = RemovePaneFromDocks(docks, panes[ii]) - panes.pop(ii) - break - - # find out where the new pane would be - allow, hint = self.DoDrop(docks, panes, hint, pt, offset) - - if not allow: - return rect - - panes.append(hint) - - sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False) - - client_size = self._frame.GetClientSize() - sizer.SetDimension(0, 0, client_size.x, client_size.y) - sizer.Layout() - - sought = "__HINT__" - - # For a notebook page, actually look for the notebook itself. - if hint.IsNotebookPage(): - id = hint.notebook_id - for pane in panes: - if pane.IsNotebookControl() and pane.notebook_id==id: - sought = pane.name - break - - for part in uiparts: - if part.pane and part.pane.name == sought: - rect.Union(wx.RectPS(part.sizer_item.GetPosition(), - part.sizer_item.GetSize())) - - sizer.Destroy() - - # check for floating frame ... - if rect.IsEmpty(): - for p in panes: - if p.name == sought and p.IsFloating(): - return wx.RectPS(p.floating_pos, p.floating_size) - - if rect.IsEmpty(): - return rect - - # actually show the hint rectangle on the screen - rect.x, rect.y = self._frame.ClientToScreen((rect.x, rect.y)) - if self._frame.GetLayoutDirection() == wx.Layout_RightToLeft: - # Mirror rectangle in RTL mode - rect.x -= rect.GetWidth() - - return rect - - - def DrawHintRect(self, pane_window, pt, offset): - """ - Calculates the hint rectangle by calling :meth:`CalculateHintRect`. If there is a - rectangle, it shows it by calling :meth:`ShowHint`, otherwise it hides any hint - rectangle currently shown. - - :param Window `pane_window`: it is the window pointer of the pane being dragged; - :param Point `pt`: is the mouse position, in client coordinates; - :param Point `offset`: describes the offset that the mouse is from the upper-left - corner of the item being dragged. - """ - - rect = self.CalculateHintRect(pane_window, pt, offset) - - if rect.IsEmpty(): - self.HideHint() - self._hint_rect = wx.Rect() - else: - self.ShowHint(rect) - self._hint_rect = wx.Rect(*rect) - - - def GetPartSizerRect(self, uiparts): - """ - Returns the rectangle surrounding the specified UI parts. - - :param list `uiparts`: list of :class:`AuiDockUIPart` parts. - """ - - rect = wx.Rect() - - for part in self._uiparts: - if part.pane and part.pane.name == "__HINT__": - rect.Union(wx.RectPS(part.sizer_item.GetPosition(), - part.sizer_item.GetSize())) - - return rect - - - def GetAttributes(self, pane): - """ - Returns all the attributes of a :class:`AuiPaneInfo`. - - :param `pane`: a :class:`AuiPaneInfo` instance. - """ - - attrs = [] - attrs.extend([pane.window, pane.frame, pane.state, pane.dock_direction, - pane.dock_layer, pane.dock_pos, pane.dock_row, pane.dock_proportion, - pane.floating_pos, pane.floating_size, pane.best_size, - pane.min_size, pane.max_size, pane.caption, pane.name, - pane.buttons, pane.rect, pane.icon, pane.notebook_id, - pane.transparent, pane.snapped, pane.minimize_mode, pane.minimize_target]) - - return attrs - - - def SetAttributes(self, pane, attrs): - """ - Sets all the attributes contained in `attrs` to a :class:`AuiPaneInfo`. - - :param `pane`: a :class:`AuiPaneInfo` instance; - :param list `attrs`: a list of attributes. - """ - - pane.window = attrs[0] - pane.frame = attrs[1] - pane.state = attrs[2] - pane.dock_direction = attrs[3] - pane.dock_layer = attrs[4] - pane.dock_pos = attrs[5] - pane.dock_row = attrs[6] - pane.dock_proportion = attrs[7] - pane.floating_pos = attrs[8] - pane.floating_size = attrs[9] - pane.best_size = attrs[10] - pane.min_size = attrs[11] - pane.max_size = attrs[12] - pane.caption = attrs[13] - pane.name = attrs[14] - pane.buttons = attrs[15] - pane.rect = attrs[16] - pane.icon = attrs[17] - pane.notebook_id = attrs[18] - pane.transparent = attrs[19] - pane.snapped = attrs[20] - pane.minimize_mode = attrs[21] - pane.minimize_target = attrs[22] - - return pane - - - def OnFloatingPaneResized(self, wnd, size): - """ - Handles the resizing of a floating pane. - - :param Window `wnd`: the window managed by the pane; - :param Size `size`: the new pane floating size. - """ - - # try to find the pane - pane = self.GetPane(wnd) - if not pane.IsOk(): - raise Exception("Pane window not found") - - if pane.frame: - indx = self._panes.index(pane) - pane.floating_pos = pane.frame.GetPosition() - pane.floating_size = size - self._panes[indx] = pane - if pane.IsSnappable(): - self.SnapPane(pane, pane.floating_pos, pane.floating_size, True) - - - def OnFloatingPaneClosed(self, wnd, event): - """ - Handles the close event of a floating pane. - - :param Window `wnd`: the window managed by the pane; - :param `event`: a :class:`CloseEvent` to be processed. - """ - - # try to find the pane - pane = self.GetPane(wnd) - if not pane.IsOk(): - raise Exception("Pane window not found") - - # fire pane close event - e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE) - e.SetPane(pane) - e.SetCanVeto(event.CanVeto()) - self.ProcessMgrEvent(e) - - if e.GetVeto(): - event.Veto() - return - else: - # close the pane, but check that it - # still exists in our pane array first - # (the event handler above might have removed it) - - check = self.GetPane(wnd) - if check.IsOk(): - self.ClosePane(pane) - - - def OnFloatingPaneActivated(self, wnd): - """ - Handles the activation event of a floating pane. - - :param Window `wnd`: the window managed by the pane. - """ - - pane = self.GetPane(wnd) - if not pane.IsOk(): - raise Exception("Pane window not found") - - if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE: - ret, self._panes = SetActivePane(self._panes, wnd) - self.RefreshCaptions() - self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, wnd, canVeto=False) - - - def OnFloatingPaneMoved(self, wnd, eventOrPt): - """ - Handles the move event of a floating pane. - - :param Window `wnd`: the window managed by the pane; - :param `eventOrPt`: a :class:`MoveEvent` to be processed or an instance of :class:`Point`. - """ - - pane = self.GetPane(wnd) - if not pane.IsOk(): - raise Exception("Pane window not found") - - if not pane.IsSnappable(): - return - - if isinstance(eventOrPt, wx.Point): - pane_pos = wx.Point(*eventOrPt) - else: - pane_pos = eventOrPt.GetPosition() - - pane_size = pane.floating_size - - self.SnapPane(pane, pane_pos, pane_size, False) - - - def SnapPane(self, pane, pane_pos, pane_size, toSnap=False): - """ - Snaps a floating pane to one of the main frame sides. - - :param `pane`: a :class:`AuiPaneInfo` instance; - :param Point `pane_pos`: the new pane floating position; - :param Size `pane_size`: the new pane floating size; - :param bool `toSnap`: a bool variable to check if :meth:`SnapPane` was called from - a move event. - """ - - if self._from_move: - return - - managed_window = self.GetManagedWindow() - wnd_pos = managed_window.GetPosition() - wnd_size = managed_window.GetSize() - snapX, snapY = self._snap_limits - - if not toSnap: - pane.snapped = 0 - if pane.IsLeftSnappable(): - # Check if we can snap to the left - diff = wnd_pos.x - (pane_pos.x + pane_size.x) - if -snapX <= diff <= snapX: - pane.snapped = wx.LEFT - pane.floating_pos = wx.Point(wnd_pos.x-pane_size.x, pane_pos.y) - elif pane.IsTopSnappable(): - # Check if we can snap to the top - diff = wnd_pos.y - (pane_pos.y + pane_size.y) - if -snapY <= diff <= snapY: - pane.snapped = wx.TOP - pane.floating_pos = wx.Point(pane_pos.x, wnd_pos.y-pane_size.y) - elif pane.IsRightSnappable(): - # Check if we can snap to the right - diff = pane_pos.x - (wnd_pos.x + wnd_size.x) - if -snapX <= diff <= snapX: - pane.snapped = wx.RIGHT - pane.floating_pos = wx.Point(wnd_pos.x + wnd_size.x, pane_pos.y) - elif pane.IsBottomSnappable(): - # Check if we can snap to the bottom - diff = pane_pos.y - (wnd_pos.y + wnd_size.y) - if -snapY <= diff <= snapY: - pane.snapped = wx.BOTTOM - pane.floating_pos = wx.Point(pane_pos.x, wnd_pos.y + wnd_size.y) - - self.RepositionPane(pane, wnd_pos, wnd_size) - - - def RepositionPane(self, pane, wnd_pos, wnd_size): - """ - Repositions a pane after the main frame has been moved/resized. - - :param `pane`: a :class:`AuiPaneInfo` instance; - :param Point `wnd_pos`: the main frame position; - :param Size `wnd_size`: the main frame size. - """ - - pane_pos = pane.floating_pos - pane_size = pane.floating_size - - snap = pane.snapped - if snap == wx.LEFT: - floating_pos = wx.Point(wnd_pos.x - pane_size.x, pane_pos.y) - elif snap == wx.TOP: - floating_pos = wx.Point(pane_pos.x, wnd_pos.y - pane_size.y) - elif snap == wx.RIGHT: - floating_pos = wx.Point(wnd_pos.x + wnd_size.x, pane_pos.y) - elif snap == wx.BOTTOM: - floating_pos = wx.Point(pane_pos.x, wnd_pos.y + wnd_size.y) - - if snap: - if pane_pos != floating_pos: - pane.floating_pos = floating_pos - self._from_move = True - pane.frame.SetPosition(pane.floating_pos) - self._from_move = False - - - def OnGripperClicked(self, pane_window, start, offset): - """ - Handles the mouse click on the pane gripper. - - :param Window `pane_window`: the window managed by the pane; - :param Point `start`: the mouse-click position; - :param Point `offset`: an offset point from the `start` position. - """ - - # try to find the pane - paneInfo = self.GetPane(pane_window) - - if not paneInfo.IsOk(): - raise Exception("Pane window not found") - - if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE: - # set the caption as active - ret, self._panes = SetActivePane(self._panes, pane_window) - self.RefreshCaptions() - self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, pane_window, canVeto=False) - - self._action_part = None - self._action_pane = paneInfo - self._action_window = pane_window - self._action_start = start - self._action_offset = offset - self._toolbar_action_offset = wx.Point(*self._action_offset) - - self._frame.CaptureMouse() - - if paneInfo.IsDocked(): - self._action = actionClickCaption - else: - if paneInfo.IsToolbar(): - self._action = actionDragToolbarPane - else: - self._action = actionDragFloatingPane - - if paneInfo.frame: - - windowPt = paneInfo.frame.GetRect().GetTopLeft() - originPt = paneInfo.frame.ClientToScreen(wx.Point()) - self._action_offset += originPt - windowPt - self._toolbar_action_offset = wx.Point(*self._action_offset) - - if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG: - paneInfo.frame.SetTransparent(150) - - if paneInfo.IsToolbar(): - self._frame.SetCursor(wx.StockCursor(wx.CURSOR_SIZING)) - - - def OnRender(self, event): - """ - Draws all of the pane captions, sashes, backgrounds, captions, grippers, pane borders and buttons. - It renders the entire user interface. It binds the ``EVT_AUI_RENDER`` event. - - :param `event`: an instance of :class:`AuiManagerEvent`. - """ - - # if the frame is about to be deleted, don't bother - if not self._frame or self._frame.IsBeingDeleted(): - return - - if not self._frame.GetSizer(): - return - - mouse = wx.GetMouseState() - mousePos = wx.Point(mouse.GetX(), mouse.GetY()) - point = self._frame.ScreenToClient(mousePos) - art = self._art - - dc = event.GetDC() - - for part in self._uiparts: - - # don't draw hidden pane items or items that aren't windows - if part.sizer_item and ((not part.sizer_item.IsWindow() and \ - not part.sizer_item.IsSpacer() and \ - not part.sizer_item.IsSizer()) or \ - not part.sizer_item.IsShown()): - - continue - - ptype = part.type - - # Let's not allocate a list inside a loop, inside a paint event... - #if ptype in [AuiDockUIPart.typesDockSizer, AuiDockUIPart.typePaneSizer]: - if ptype == AuiDockUIPart.typeDockSizer or ptype == AuiDockUIPart.typePaneSizer: - art.DrawSash(dc, self._frame, part.orientation, part.rect) - - elif ptype == AuiDockUIPart.typeBackground: - art.DrawBackground(dc, self._frame, part.orientation, part.rect) - - elif ptype == AuiDockUIPart.typeCaption: - art.DrawCaption(dc, self._frame, part.pane.caption, part.rect, part.pane) - - elif ptype == AuiDockUIPart.typeGripper: - art.DrawGripper(dc, self._frame, part.rect, part.pane) - - elif ptype == AuiDockUIPart.typePaneBorder: - art.DrawBorder(dc, self._frame, part.rect, part.pane) - - elif ptype == AuiDockUIPart.typePaneButton: - self.DrawPaneButton(dc, part, point) - - - def Repaint(self, dc=None): - """ - Repaints the entire frame decorations (sashes, borders, buttons and so on). - It renders the entire user interface. - - :param `dc`: if not ``None``, an instance of :class:`PaintDC`. - """ - - w, h = self._frame.GetClientSize() - - # Figure out which dc to use; if one - # has been specified, use it, otherwise - # make a client dc - if dc is None: - client_dc = wx.ClientDC(self._frame) - dc = client_dc - - # If the frame has a toolbar, the client area - # origin will not be (0, 0). - pt = self._frame.GetClientAreaOrigin() - if pt.x != 0 or pt.y != 0: - dc.SetDeviceOrigin(pt.x, pt.y) - - # Render all the items - self.Render(dc) - - - def Render(self, dc): - """ - Fires a render event, which is normally handled by :meth:`OnRender`. This allows the - render function to be overridden via the render event. - - This can be useful for painting custom graphics in the main window. - Default behavior can be invoked in the overridden function by calling - :meth:`OnRender`. - - :param `dc`: a :class:`DC` device context object. - """ - - e = AuiManagerEvent(wxEVT_AUI_RENDER) - e.SetManager(self) - e.SetDC(dc) - self.ProcessMgrEvent(e) - - - def OnCaptionDoubleClicked(self, pane_window): - """ - Handles the mouse double click on the pane caption. - - :param Window `pane_window`: the window managed by the pane. - """ - - # try to find the pane - paneInfo = self.GetPane(pane_window) - if not paneInfo.IsOk(): - raise Exception("Pane window not found") - - if not paneInfo.IsFloatable() or not paneInfo.IsDockable() or \ - self._agwFlags & AUI_MGR_ALLOW_FLOATING == 0: - return - - indx = self._panes.index(paneInfo) - win_rect = None - - if paneInfo.IsFloating(): - if paneInfo.name.startswith("__floating__"): - # It's a floating tab from a AuiNotebook - notebook = paneInfo.window.__aui_notebook__ - notebook.ReDockPage(paneInfo) - self.Update() - return - else: - - e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True) - if e.GetVeto(): - self.HideHint() - ShowDockingGuides(self._guides, False) - return - - win_rect = paneInfo.frame.GetRect() - paneInfo.Dock() - if paneInfo.IsToolbar(): - paneInfo = self.SwitchToolBarOrientation(paneInfo) - - e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False) - - else: - - e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, paneInfo, canVeto=True) - if e.GetVeto(): - return - - # float the window - if paneInfo.IsMaximized(): - self.RestorePane(paneInfo) - - if paneInfo.floating_pos == wx.Point(-1, -1): - captionSize = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE) - paneInfo.floating_pos = pane_window.GetScreenPosition() - paneInfo.floating_pos.y -= captionSize - - paneInfo.Float() - e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, paneInfo, canVeto=False) - - self._panes[indx] = paneInfo - self.Update() - - if win_rect and self._agwFlags & AUI_MGR_ANIMATE_FRAMES: - paneInfo = self.GetPane(pane_window) - pane_rect = paneInfo.window.GetScreenRect() - self.AnimateDocking(win_rect, pane_rect) - - - def OnPaint(self, event): - """ - Handles the ``wx.EVT_PAINT`` event for :class:`AuiManager`. - - :param `event`: an instance of :class:`PaintEvent` to be processed. - """ - - dc = wx.PaintDC(self._frame) - self.Repaint(dc) - - - def OnEraseBackground(self, event): - """ - Handles the ``wx.EVT_ERASE_BACKGROUND`` event for :class:`AuiManager`. - - :param `event`: :class:`EraseEvent` to be processed. - - :note: This is intentionally empty (excluding wxMAC) to reduce - flickering while drawing. - """ - - if wx.Platform == "__WXMAC__": - event.Skip() - - - def OnSize(self, event): - """ - Handles the ``wx.EVT_SIZE`` event for :class:`AuiManager`. - - :param `event`: a :class:`SizeEvent` to be processed. - """ - - skipped = False - if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen(): - skipped = True - event.Skip() - - if self._frame: - - self.DoFrameLayout() - if wx.Platform == "__WXMAC__": - self._frame.Refresh() - else: - self.Repaint() - - if isinstance(self._frame, wx.MDIParentFrame) or isinstance(self._frame, tabmdi.AuiMDIClientWindow) \ - or isinstance(self._frame, tabmdi.AuiMDIParentFrame): - # for MDI parent frames, this event must not - # be "skipped". In other words, the parent frame - # must not be allowed to resize the client window - # after we are finished processing sizing changes - return - - if not skipped: - event.Skip() - - # For the snap to screen... - self.OnMove(None) - - - def OnFindManager(self, event): - """ - Handles the ``EVT_AUI_FIND_MANAGER`` event for :class:`AuiManager`. - - :param `event`: a :class:`AuiManagerEvent` event to be processed. - """ - - # Initialize to None - event.SetManager(None) - - if not self._frame: - return - - # See it this window wants to overwrite - self._frame.ProcessEvent(event) - - # if no, it must be us - if not event.GetManager(): - event.SetManager(self) - - - def OnSetCursor(self, event): - """ - Handles the ``wx.EVT_SET_CURSOR`` event for :class:`AuiManager`. - - :param `event`: a :class:`SetCursorEvent` to be processed. - """ - - # determine cursor - part = self.HitTest(event.GetX(), event.GetY()) - cursor = wx.NullCursor - - if part: - if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]: - - if not self.CheckMovableSizer(part): - return - - if part.orientation == wx.VERTICAL: - cursor = wx.StockCursor(wx.CURSOR_SIZEWE) - else: - cursor = wx.StockCursor(wx.CURSOR_SIZENS) - - elif part.type == AuiDockUIPart.typeGripper: - cursor = wx.StockCursor(wx.CURSOR_SIZING) - - event.SetCursor(cursor) - - - def UpdateButtonOnScreen(self, button_ui_part, event): - """ - Updates/redraws the UI part containing a pane button. - - :param AuiDockUIPart `button_ui_part`: the UI part the button belongs to; - :param `event`: a :class:`MouseEvent` to be processed. - """ - - hit_test = self.HitTest(*event.GetPosition()) - - if not hit_test or not button_ui_part: - return - - state = AUI_BUTTON_STATE_NORMAL - - if hit_test == button_ui_part: - if event.LeftDown(): - state = AUI_BUTTON_STATE_PRESSED - else: - state = AUI_BUTTON_STATE_HOVER - else: - if event.LeftDown(): - state = AUI_BUTTON_STATE_HOVER - - # now repaint the button with hover state - cdc = wx.ClientDC(self._frame) - - # if the frame has a toolbar, the client area - # origin will not be (0,0). - pt = self._frame.GetClientAreaOrigin() - if pt.x != 0 or pt.y != 0: - cdc.SetDeviceOrigin(pt.x, pt.y) - - if hit_test.pane: - self._art.DrawPaneButton(cdc, self._frame, - button_ui_part.button.button_id, - state, - button_ui_part.rect, hit_test.pane) - - - def OnLeftDown(self, event): - """ - Handles the ``wx.EVT_LEFT_DOWN`` event for :class:`AuiManager`. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - part = self.HitTest(*event.GetPosition()) - - if not part: - event.Skip() - return - - self._currentDragItem = -1 - - if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]: - - if not self.CheckMovableSizer(part): - return - - self._action = actionResize - self._action_part = part - self._action_pane = None - self._action_rect = wx.Rect() - self._action_start = wx.Point(event.GetX(), event.GetY()) - self._action_offset = wx.Point(event.GetX() - part.rect.x, - event.GetY() - part.rect.y) - - # draw the resize hint - rect = wx.RectPS(self._frame.ClientToScreen(part.rect.GetPosition()), - part.rect.GetSize()) - - self._action_rect = wx.Rect(*rect) - - if not AuiManager_HasLiveResize(self): - if wx.Platform == "__WXMAC__": - dc = wx.ClientDC(self._frame) - else: - dc = wx.ScreenDC() - - DrawResizeHint(dc, rect) - - self._frame.CaptureMouse() - - elif part.type == AuiDockUIPart.typePaneButton: - if self.IsPaneButtonVisible(part): - self._action = actionClickButton - self._action_part = part - self._action_pane = None - self._action_start = wx.Point(*event.GetPosition()) - self._frame.CaptureMouse() - - self.RefreshButton(part) - - elif part.type in [AuiDockUIPart.typeCaption, AuiDockUIPart.typeGripper]: - - # if we are managing a AuiFloatingFrame window, then - # we are an embedded AuiManager inside the AuiFloatingFrame. - # We want to initiate a toolbar drag in our owner manager - if isinstance(part.pane.window.GetParent(), AuiFloatingFrame): - rootManager = GetManager(part.pane.window) - else: - rootManager = self - - offset = wx.Point(event.GetX() - part.rect.x, event.GetY() - part.rect.y) - rootManager.OnGripperClicked(part.pane.window, event.GetPosition(), offset) - - if wx.Platform != "__WXMAC__": - event.Skip() - - - def OnLeftDClick(self, event): - """ - Handles the ``wx.EVT_LEFT_DCLICK`` event for :class:`AuiManager`. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - part = self.HitTest(event.GetX(), event.GetY()) - - if part and part.type == AuiDockUIPart.typeCaption: - if isinstance(part.pane.window.GetParent(), AuiFloatingFrame): - rootManager = GetManager(part.pane.window) - else: - rootManager = self - - rootManager.OnCaptionDoubleClicked(part.pane.window) - - elif part and part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]: - # Handles double click on AuiNotebook sashes to unsplit - sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE) - for child in part.cont_sizer.GetChildren(): - if child.IsSizer(): - win = child.GetSizer().GetContainingWindow() - if isinstance(win, auibook.AuiNotebook): - win.UnsplitDClick(part, sash_size, event.GetPosition()) - break - - event.Skip() - - - def DoEndResizeAction(self, event): - """ - Ends a resize action, or for live update, resizes the sash. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - clientPt = event.GetPosition() - screenPt = self._frame.ClientToScreen(clientPt) - - return self.RestrictResize(clientPt, screenPt, createDC=False) - - - def RestrictResize(self, clientPt, screenPt, createDC): - """ Common method between :meth:`DoEndResizeAction` and :meth:`OnLeftUp_Resize`. """ - - dock = self._action_part.dock - pane = self._action_part.pane - - if createDC: - if wx.Platform == "__WXMAC__": - dc = wx.ClientDC(self._frame) - else: - dc = wx.ScreenDC() - - DrawResizeHint(dc, self._action_rect) - self._action_rect = wx.Rect() - - newPos = clientPt - self._action_offset - - if self._action_part.type == AuiDockUIPart.typeDockSizer: - minPix, maxPix = self.CalculateDockSizerLimits(dock) - else: - if not self._action_part.pane: - return - minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane) - - if self._action_part.orientation == wx.HORIZONTAL: - newPos.y = Clip(newPos.y, minPix, maxPix) - else: - newPos.x = Clip(newPos.x, minPix, maxPix) - - if self._action_part.type == AuiDockUIPart.typeDockSizer: - - partnerDock = self.GetPartnerDock(dock) - sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE) - new_dock_size = 0 - direction = dock.dock_direction - - if direction == AUI_DOCK_LEFT: - new_dock_size = newPos.x - dock.rect.x - - elif direction == AUI_DOCK_TOP: - new_dock_size = newPos.y - dock.rect.y - - elif direction == AUI_DOCK_RIGHT: - new_dock_size = dock.rect.x + dock.rect.width - newPos.x - sash_size - - elif direction == AUI_DOCK_BOTTOM: - new_dock_size = dock.rect.y + dock.rect.height - newPos.y - sash_size - - deltaDockSize = new_dock_size - dock.size - - if partnerDock: - if deltaDockSize > partnerDock.size - sash_size: - deltaDockSize = partnerDock.size - sash_size - - partnerDock.size -= deltaDockSize - - dock.size += deltaDockSize - self.Update() - - else: - - # determine the new pixel size that the user wants - # this will help us recalculate the pane's proportion - if dock.IsHorizontal(): - oldPixsize = pane.rect.width - newPixsize = oldPixsize + newPos.x - self._action_part.rect.x - - else: - oldPixsize = pane.rect.height - newPixsize = oldPixsize + newPos.y - self._action_part.rect.y - - totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock) - partnerPane = self.GetPartnerPane(dock, pane) - - # prevent division by zero - if totalPixsize <= 0 or totalProportion <= 0 or not partnerPane: - return - - # adjust for the surplus - while (oldPixsize > 0 and totalPixsize > 10 and \ - oldPixsize*totalProportion/totalPixsize < pane.dock_proportion): - - totalPixsize -= 1 - - # calculate the new proportion of the pane - - newProportion = newPixsize*totalProportion/totalPixsize - newProportion = Clip(newProportion, 1, totalProportion) - deltaProp = newProportion - pane.dock_proportion - - if partnerPane.dock_proportion - deltaProp < 1: - deltaProp = partnerPane.dock_proportion - 1 - newProportion = pane.dock_proportion + deltaProp - - # borrow the space from our neighbor pane to the - # right or bottom (depending on orientation) - partnerPane.dock_proportion -= deltaProp - pane.dock_proportion = newProportion - - self.Update() - - return True - - - def OnLeftUp(self, event): - """ - Handles the ``wx.EVT_LEFT_UP`` event for :class:`AuiManager`. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - if self._action == actionResize: -## self._frame.Freeze() - self.OnLeftUp_Resize(event) -## self._frame.Thaw() - - elif self._action == actionClickButton: - self.OnLeftUp_ClickButton(event) - - elif self._action == actionDragFloatingPane: - self.OnLeftUp_DragFloatingPane(event) - - elif self._action == actionDragToolbarPane: - self.OnLeftUp_DragToolbarPane(event) - - elif self._action == actionDragMovablePane: - self.OnLeftUp_DragMovablePane(event) - - else: - event.Skip() - - try: - if self._frame.HasCapture(): - self._frame.ReleaseMouse() - except wx.PyDeadObjectError: - pass - - self._action = actionNone - - - def OnMotion(self, event): - """ - Handles the ``wx.EVT_MOTION`` event for :class:`AuiManager`. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - if self._action == actionResize: - self.OnMotion_Resize(event) - - elif self._action == actionClickCaption: - self.OnMotion_ClickCaption(event) - - elif self._action == actionDragFloatingPane: - self.OnMotion_DragFloatingPane(event) - - elif self._action == actionDragToolbarPane: - self.OnMotion_DragToolbarPane(event) - - elif self._action == actionDragMovablePane: - self.OnMotion_DragMovablePane(event) - - else: - self.OnMotion_Other(event) - - - def OnLeaveWindow(self, event): - """ - Handles the ``wx.EVT_LEAVE_WINDOW`` event for :class:`AuiManager`. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - if self._hover_button: - self.RefreshButton(self._hover_button) - self._hover_button = None - - - def OnCaptureLost(self, event): - """ - Handles the ``wx.EVT_MOUSE_CAPTURE_LOST`` event for :class:`AuiManager`. - - :param `event`: a :class:`MouseCaptureLostEvent` to be processed. - """ - - # cancel the operation in progress, if any - if self._action != actionNone: - self._action = actionNone - self.HideHint() - - - def OnHintFadeTimer(self, event): - """ - Handles the ``wx.EVT_TIMER`` event for :class:`AuiManager`. - - :param `event`: a :class:`TimerEvent` to be processed. - """ - - if not self._hint_window or self._hint_fadeamt >= self._hint_fademax: - self._hint_fadetimer.Stop() - return - - self._hint_fadeamt += 4 - self._hint_window.SetTransparent(self._hint_fadeamt) - - - def OnMove(self, event): - """ - Handles the ``wx.EVT_MOVE`` event for :class:`AuiManager`. - - :param `event`: a :class:`MoveEvent` to be processed. - """ - - if event is not None: - event.Skip() - - if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen(): - return - - docked, hAlign, vAlign, monitor = self._is_docked - if docked: - self.Snap() - - for pane in self._panes: - if pane.IsSnappable(): - if pane.IsFloating() and pane.IsShown(): - self.SnapPane(pane, pane.floating_pos, pane.floating_size, True) - - - def OnSysColourChanged(self, event): - """ - Handles the ``wx.EVT_SYS_COLOUR_CHANGED`` event for :class:`AuiManager`. - - :param `event`: a :class:`SysColourChangedEvent` to be processed. - """ - - # This event is probably triggered by a theme change - # so we have to re-init the art provider. - if self._art: - self._art.Init() - - if self._frame: - self.Update() - self._frame.Refresh() - - - def OnChildFocus(self, event): - """ - Handles the ``wx.EVT_CHILD_FOCUS`` event for :class:`AuiManager`. - - :param `event`: a :class:`ChildFocusEvent` to be processed. - """ - - # when a child pane has it's focus set, we should change the - # pane's active state to reflect this. (this is only true if - # active panes are allowed by the owner) - - window = event.GetWindow() - if isinstance(window, wx.Dialog): - # Ignore EVT_CHILD_FOCUS events originating from dialogs not - # managed by AUI - rootManager = None - elif isinstance(window.GetParent(), AuiFloatingFrame): - rootManager = GetManager(window) - else: - rootManager = self - - if rootManager: - rootManager.ActivatePane(window) - - event.Skip() - - - def OnMotion_ClickCaption(self, event): - """ - Sub-handler for the :meth:`OnMotion` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - clientPt = event.GetPosition() - screenPt = self._frame.ClientToScreen(clientPt) - - drag_x_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_X) - drag_y_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_Y) - - if not self._action_pane: - return - - # we need to check if the mouse is now being dragged - if not (abs(clientPt.x - self._action_start.x) > drag_x_threshold or \ - abs(clientPt.y - self._action_start.y) > drag_y_threshold): - - return - - # dragged -- we need to change the mouse action to 'drag' - if self._action_pane.IsToolbar(): - self._action = actionDragToolbarPane - self._action_window = self._action_pane.window - - elif self._action_pane.IsFloatable() and self._agwFlags & AUI_MGR_ALLOW_FLOATING: - - e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, self._action_pane, canVeto=True) - if e.GetVeto(): - return - - self._action = actionDragFloatingPane - - # set initial float position - self._action_pane.floating_pos = screenPt - self._action_offset - - # float the window - if self._action_pane.IsMaximized(): - self.RestorePane(self._action_pane) - - self._action_pane.Hide() - self._action_pane.Float() - if wx.Platform == "__WXGTK__": - self._action_pane.Show() - - e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, self._action_pane, canVeto=False) - - if not self._action_pane.frame: - self.Update() - - self._action_window = self._action_pane.window - - # adjust action offset for window frame - windowPt = self._action_pane.frame.GetRect().GetTopLeft() - originPt = self._action_pane.frame.ClientToScreen(wx.Point()) - self._toolbar_action_offset = originPt - windowPt - - if self._agwFlags & AUI_MGR_USE_NATIVE_MINIFRAMES: - originPt = windowPt + wx.Point(3, 3) - - self._action_offset += originPt - windowPt - - # action offset is used here to make it feel "natural" to the user - # to drag a docked pane and suddenly have it become a floating frame. - # Sometimes, however, the offset where the user clicked on the docked - # caption is bigger than the width of the floating frame itself, so - # in that case we need to set the action offset to a sensible value - frame_size = self._action_pane.frame.GetSize() - if self._action_offset.x > frame_size.x * 2 / 3: - self._action_offset.x = frame_size.x / 2 - if self._action_offset.y > frame_size.y * 2 / 3: - self._action_offset.y = frame_size.y / 2 - - self.OnMotion_DragFloatingPane(event) - if wx.Platform != "__WXGTK__": - self._action_pane.Show() - - self.Update() - - elif self._action_pane.IsMovable(): - self._action = actionDragMovablePane - self._action_window = self._action_pane.window - - - def OnMotion_Resize(self, event): - """ - Sub-handler for the :meth:`OnMotion` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - if AuiManager_HasLiveResize(self): - if self._currentDragItem != -1: - self._action_part = self._uiparts[self._currentDragItem] - else: - self._currentDragItem = self._uiparts.index(self._action_part) - - if self._frame.HasCapture(): - self._frame.ReleaseMouse() - - self.DoEndResizeAction(event) - self._frame.CaptureMouse() - return - - if not self._action_part or not self._action_part.dock or not self._action_part.orientation: - return - - clientPt = event.GetPosition() - screenPt = self._frame.ClientToScreen(clientPt) - - dock = self._action_part.dock - pos = self._action_part.rect.GetPosition() - - if self._action_part.type == AuiDockUIPart.typeDockSizer: - minPix, maxPix = self.CalculateDockSizerLimits(dock) - else: - if not self._action_part.pane: - return - - pane = self._action_part.pane - minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane) - - if self._action_part.orientation == wx.HORIZONTAL: - pos.y = Clip(clientPt.y - self._action_offset.y, minPix, maxPix) - else: - pos.x = Clip(clientPt.x - self._action_offset.x, minPix, maxPix) - - hintrect = wx.RectPS(self._frame.ClientToScreen(pos), self._action_part.rect.GetSize()) - - if hintrect != self._action_rect: - - if wx.Platform == "__WXMAC__": - dc = wx.ClientDC(self._frame) - else: - dc = wx.ScreenDC() - - DrawResizeHint(dc, self._action_rect) - DrawResizeHint(dc, hintrect) - self._action_rect = wx.Rect(*hintrect) - - - def OnLeftUp_Resize(self, event): - """ - Sub-handler for the :meth:`OnLeftUp` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - if self._currentDragItem != -1 and AuiManager_HasLiveResize(self): - self._action_part = self._uiparts[self._currentDragItem] - - if self._frame.HasCapture(): - self._frame.ReleaseMouse() - - self.DoEndResizeAction(event) - self._currentDragItem = -1 - return - - if not self._action_part or not self._action_part.dock: - return - - clientPt = event.GetPosition() - screenPt = self._frame.ClientToScreen(clientPt) - - return self.RestrictResize(clientPt, screenPt, createDC=True) - - - def OnLeftUp_ClickButton(self, event): - """ - Sub-handler for the :meth:`OnLeftUp` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - self._hover_button = None - - if self._action_part: - self.RefreshButton(self._action_part) - - # make sure we're still over the item that was originally clicked - if self._action_part == self.HitTest(*event.GetPosition()): - - # fire button-click event - e = AuiManagerEvent(wxEVT_AUI_PANE_BUTTON) - e.SetManager(self) - e.SetPane(self._action_part.pane) - e.SetButton(self._action_part.button.button_id) - self.ProcessMgrEvent(e) - - - def CheckPaneMove(self, pane): - """ - Checks if a pane has moved by a visible amount. - - :param `pane`: an instance of :class:`AuiPaneInfo`. - """ - - win_rect = pane.frame.GetRect() - win_rect.x, win_rect.y = pane.floating_pos - - if win_rect == self._last_rect: - return False - - # skip the first move event - if self._last_rect.IsEmpty(): - self._last_rect = wx.Rect(*win_rect) - return False - - # skip if moving too fast to avoid massive redraws and - # jumping hint windows - if abs(win_rect.x - self._last_rect.x) > 10 or \ - abs(win_rect.y - self._last_rect.y) > 10: - self._last_rect = wx.Rect(*win_rect) - return False - - return True - - - def OnMotion_DragFloatingPane(self, eventOrPt): - """ - Sub-handler for the :meth:`OnMotion` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - isPoint = False - if isinstance(eventOrPt, wx.Point): - clientPt = self._frame.ScreenToClient(eventOrPt) - screenPt = wx.Point(*eventOrPt) - isPoint = True - else: - clientPt = eventOrPt.GetPosition() - screenPt = self._frame.ClientToScreen(clientPt) - - framePos = wx.Point() - - # try to find the pane - pane = self.GetPane(self._action_window) - if not pane.IsOk(): - raise Exception("Pane window not found") - - # update floating position - if pane.IsFloating(): - diff = pane.floating_pos - (screenPt - self._action_offset) - pane.floating_pos = screenPt - self._action_offset - - framePos = pane.floating_pos - - # Move the pane window - if pane.frame: - - if diff.x != 0 or diff.y != 0: - if wx.Platform == "__WXMSW__" and (self._agwFlags & AUI_MGR_TRANSPARENT_DRAG) == 0: # and not self.CheckPaneMove(pane): - # return - # HACK: Terrible hack on wxMSW (!) - pane.frame.SetTransparent(254) - - self._from_move = True - pane.frame.Move(pane.floating_pos) - self._from_move = False - - if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG: - pane.frame.SetTransparent(150) - - # calculate the offset from the upper left-hand corner - # of the frame to the mouse pointer - action_offset = screenPt - framePos - - # is the pane dockable? - if not self.CanDockPanel(pane): - self.HideHint() - ShowDockingGuides(self._guides, False) - return - - for paneInfo in self._panes: - - if not paneInfo.IsDocked() or not paneInfo.IsShown(): - continue - if paneInfo.IsToolbar() or paneInfo.IsNotebookControl(): - continue - if paneInfo.IsMaximized(): - continue - - if paneInfo.IsNotebookPage(): - - notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id) - - if not notebookRoot or not notebookRoot.IsDocked(): - continue - - rc = paneInfo.window.GetScreenRect() - if rc.Contains(screenPt): - if rc.height < 20 or rc.width < 20: - return - - self.UpdateDockingGuides(paneInfo) - ShowDockingGuides(self._guides, True) - break - - self.DrawHintRect(pane.window, clientPt, action_offset) - - - def OnMotion_DragMovablePane(self, eventOrPt): - """ - Sub-handler for the :meth:`OnMotion` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - # Try to find the pane. - pane = self.GetPane(self._action_window) - if not pane.IsOk(): - raise Exception("Pane window not found") - - # Draw a hint for where the window will be moved. - if isinstance(eventOrPt, wx.Point): - pt = wx.Point(*eventOrPt) - else: - pt = eventOrPt.GetPosition() - - self.DrawHintRect(self._action_window, pt, wx.Point(0, 0)) - - # Reduces flicker. - self._frame.Update() - - - def OnLeftUp_DragFloatingPane(self, eventOrPt): - """ - Sub-handler for the :meth:`OnLeftUp` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - if isinstance(eventOrPt, wx.Point): - clientPt = self._frame.ScreenToClient(eventOrPt) - screenPt = wx.Point(*eventOrPt) - else: - clientPt = eventOrPt.GetPosition() - screenPt = self._frame.ClientToScreen(clientPt) - - # try to find the pane - paneInfo = self.GetPane(self._action_window) - if not paneInfo.IsOk(): - raise Exception("Pane window not found") - - ret = False - - if paneInfo.frame: - - # calculate the offset from the upper left-hand corner - # of the frame to the mouse pointer - framePos = paneInfo.frame.GetPosition() - action_offset = screenPt - framePos - - # is the pane dockable? - if self.CanDockPanel(paneInfo): - # do the drop calculation - indx = self._panes.index(paneInfo) - ret, paneInfo = self.DoDrop(self._docks, self._panes, paneInfo, clientPt, action_offset) - - if ret: - e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True) - if e.GetVeto(): - self.HideHint() - ShowDockingGuides(self._guides, False) - return - - e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False) - - if self._agwFlags & AUI_MGR_SMOOTH_DOCKING: - self.SmoothDock(paneInfo) - - self._panes[indx] = paneInfo - - # if the pane is still floating, update it's floating - # position (that we store) - if paneInfo.IsFloating(): - paneInfo.floating_pos = paneInfo.frame.GetPosition() - if paneInfo.frame._transparent != paneInfo.transparent or self._agwFlags & AUI_MGR_TRANSPARENT_DRAG: - paneInfo.frame.SetTransparent(paneInfo.transparent) - paneInfo.frame._transparent = paneInfo.transparent - - elif self._has_maximized: - self.RestoreMaximizedPane() - - # reorder for dropping to a new notebook - # (caution: this code breaks the reference!) - tempPaneInfo = self.CopyTarget(paneInfo) - self._panes.remove(paneInfo) - self._panes.append(tempPaneInfo) - - if ret: - self.Update() - - if tempPaneInfo.IsFloating(): - self.SnapPane(tempPaneInfo, tempPaneInfo.floating_pos, tempPaneInfo.floating_size, False) - - self.HideHint() - ShowDockingGuides(self._guides, False) - - - def OnLeftUp_DragMovablePane(self, event): - """ - Sub-handler for the :meth:`OnLeftUp` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - # Try to find the pane. - paneInfo = self.GetPane(self._action_window) - if not paneInfo.IsOk(): - raise Exception("Pane window not found") - - # Hide the hint as it is no longer needed. - self.HideHint() - - # is the pane dockable? - if self.CanDockPanel(paneInfo): - # Move the pane to new position. - pt = event.GetPosition() - # do the drop calculation - indx = self._panes.index(paneInfo) - ret, paneInfo = self.DoDrop(self._docks, self._panes, paneInfo, pt, wx.Point(0,0)) - - if ret: - e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True) - if e.GetVeto(): - self.HideHint() - ShowDockingGuides(self._guides, False) - return - - e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False) - - if self._agwFlags & AUI_MGR_SMOOTH_DOCKING: - self.SmoothDock(paneInfo) - - self._panes[indx] = paneInfo - - if ret: - # Update the layout to realize new position and e.g. form notebooks if needed. - self.Update() - - if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE: - # Ensure active before doing actual display. - ret, self._panes = SetActivePane(self._panes, paneInfo.window) - - # Make changes visible to user. - self.Repaint() - - # Cancel the action and release the mouse. - self._action = actionNone - self._frame.ReleaseMouse() - self._action_window = None - - - def OnMotion_DragToolbarPane(self, eventOrPt): - """ - Sub-handler for the :meth:`OnMotion` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - isPoint = False - if isinstance(eventOrPt, wx.Point): - clientPt = self._frame.ScreenToClient(eventOrPt) - screenPt = wx.Point(*eventOrPt) - isPoint = True - else: - clientPt = eventOrPt.GetPosition() - screenPt = self._frame.ClientToScreen(clientPt) - - pane = self.GetPane(self._action_window) - if not pane.IsOk(): - raise Exception("Pane window not found") - - pane.state |= AuiPaneInfo.actionPane - indx = self._panes.index(pane) - - ret = False - wasFloating = pane.IsFloating() - # is the pane dockable? - if self.CanDockPanel(pane): - # do the drop calculation - ret, pane = self.DoDrop(self._docks, self._panes, pane, clientPt, self._action_offset) - - # update floating position - if pane.IsFloating(): - pane.floating_pos = screenPt - self._toolbar_action_offset - - # move the pane window - if pane.frame: - if wx.Platform == "__WXMSW__" and (self._agwFlags & AUI_MGR_TRANSPARENT_DRAG) == 0: # and not self.CheckPaneMove(pane): - # return - # HACK: Terrible hack on wxMSW (!) - pane.frame.SetTransparent(254) - - self._from_move = True - pane.frame.Move(pane.floating_pos) - self._from_move = False - - if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG: - pane.frame.SetTransparent(150) - - self._panes[indx] = pane - if ret and wasFloating != pane.IsFloating() or (ret and not wasFloating): - wx.CallAfter(self.Update) - - # when release the button out of the window. - # TODO: a better fix is needed. - - if _VERSION_STRING < "2.9": - leftDown = wx.GetMouseState().LeftDown() - else: - leftDown = wx.GetMouseState().LeftIsDown() - - if not leftDown: - self._action = actionNone - self.OnLeftUp_DragToolbarPane(eventOrPt) - - - def OnMotion_Other(self, event): - """ - Sub-handler for the :meth:`OnMotion` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - part = self.HitTest(*event.GetPosition()) - - if part and part.type == AuiDockUIPart.typePaneButton \ - and self.IsPaneButtonVisible(part): - if part != self._hover_button: - - if self._hover_button: - self.RefreshButton(self._hover_button) - - self._hover_button = part - self.RefreshButton(part) - - else: - - if self._hover_button: - self.RefreshButton(self._hover_button) - else: - event.Skip() - - self._hover_button = None - - - def OnLeftUp_DragToolbarPane(self, eventOrPt): - """ - Sub-handler for the :meth:`OnLeftUp` event. - - :param `event`: a :class:`MouseEvent` to be processed. - """ - - isPoint = False - if isinstance(eventOrPt, wx.Point): - clientPt = self._frame.ScreenToClient(eventOrPt) - screenPt = wx.Point(*eventOrPt) - isPoint = True - else: - clientPt = eventOrPt.GetPosition() - screenPt = self._frame.ClientToScreen(clientPt) - - # try to find the pane - pane = self.GetPane(self._action_window) - if not pane.IsOk(): - raise Exception("Pane window not found") - - if pane.IsFloating(): - pane.floating_pos = pane.frame.GetPosition() - if pane.frame._transparent != pane.transparent or self._agwFlags & AUI_MGR_TRANSPARENT_DRAG: - pane.frame.SetTransparent(pane.transparent) - pane.frame._transparent = pane.transparent - - # save the new positions - docks = FindDocks(self._docks, pane.dock_direction, pane.dock_layer, pane.dock_row) - if len(docks) == 1: - dock = docks[0] - pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock) - - for i in xrange(len(dock.panes)): - dock.panes[i].dock_pos = pane_positions[i] - - pane.state &= ~AuiPaneInfo.actionPane - self.Update() - - - def OnPaneButton(self, event): - """ - Handles the ``EVT_AUI_PANE_BUTTON`` event for :class:`AuiManager`. - - :param `event`: a :class:`AuiManagerEvent` event to be processed. - """ - - if not event.pane: - raise Exception("Pane Info passed to AuiManager.OnPaneButton must be non-null") - - pane = event.pane - - if event.button == AUI_BUTTON_CLOSE: - - if isinstance(pane.window.GetParent(), AuiFloatingFrame): - rootManager = GetManager(pane.window) - else: - rootManager = self - - if rootManager != self: - self._frame.Close() - return - - # fire pane close event - e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE) - e.SetManager(self) - e.SetPane(event.pane) - self.ProcessMgrEvent(e) - - if not e.GetVeto(): - - # close the pane, but check that it - # still exists in our pane array first - # (the event handler above might have removed it) - check = self.GetPane(pane.window) - if check.IsOk(): - # Use the checked pane, because the ui part which - # emitted this event may actually have a pane that's - # different from the panes in self._panes. This seems - # to be a fairly endemic problem with this framework. - self.ClosePane(check) - - self.Update() - - # mn this performs the minimizing of a pane - elif event.button == AUI_BUTTON_MINIMIZE: - e = AuiManagerEvent(wxEVT_AUI_PANE_MINIMIZE) - e.SetManager(self) - e.SetPane(event.pane) - self.ProcessMgrEvent(e) - - if not e.GetVeto(): - self.MinimizePane(pane) - - elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and not pane.IsMaximized(): - - # fire pane close event - e = AuiManagerEvent(wxEVT_AUI_PANE_MAXIMIZE) - e.SetManager(self) - e.SetPane(event.pane) - self.ProcessMgrEvent(e) - - if not e.GetVeto(): - - self.MaximizePane(pane) - self.Update() - - elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and pane.IsMaximized(): - - # fire pane close event - e = AuiManagerEvent(wxEVT_AUI_PANE_RESTORE) - e.SetManager(self) - e.SetPane(event.pane) - self.ProcessMgrEvent(e) - - if not e.GetVeto(): - - self.RestorePane(pane) - self.Update() - - elif event.button == AUI_BUTTON_PIN: - - if self._agwFlags & AUI_MGR_ALLOW_FLOATING and pane.IsFloatable(): - e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, pane, canVeto=True) - if e.GetVeto(): - return - - pane.Float() - e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, pane, canVeto=False) - - self.Update() - - - def MinimizePane(self, paneInfo, mgrUpdate=True): - """ - Minimizes a pane in a newly and automatically created :class:`~lib.agw.aui.auibar.AuiToolBar`. - - Clicking on the minimize button causes a new :class:`~lib.agw.aui.auibar.AuiToolBar` to be created - and added to the frame manager (currently the implementation is such that - panes at West will have a toolbar at the right, panes at South will have - toolbars at the bottom etc...) and the pane is hidden in the manager. - - Clicking on the restore button on the newly created toolbar will result in the - toolbar being removed and the original pane being restored. - - :param `paneInfo`: a :class:`AuiPaneInfo` instance for the pane to be minimized; - :param bool `mgrUpdate`: ``True`` to call :meth:`Update` to realize the new layout, - ``False`` otherwise. - - .. note:: - - The `mgrUpdate` parameter is currently only used while loading perspectives using - :meth:`LoadPerspective`, as minimized panes were not correctly taken into account before. - - """ - - if not paneInfo.IsToolbar(): - - if paneInfo.IsMinimized() and mgrUpdate: - # We are already minimized - return - - # Basically the idea is this. - # - # 1) create a toolbar, with a restore button - # - # 2) place the new toolbar in the toolbar area representative of the location of the pane - # (NORTH/SOUTH/EAST/WEST, central area always to the right) - # - # 3) Hide the minimizing pane - - # personalize the toolbar style - - tbStyle = AUI_TB_DEFAULT_STYLE - posMask = paneInfo.minimize_mode & AUI_MINIMIZE_POS_MASK - captMask = paneInfo.minimize_mode & AUI_MINIMIZE_CAPT_MASK - dockDirection = paneInfo.dock_direction - if captMask != 0: - tbStyle |= AUI_TB_TEXT - - if posMask == AUI_MINIMIZE_POS_TOOLBAR: - minimize_toolbar = self.GetPane(paneInfo.minimize_target) - if not minimize_toolbar.IsOk(): - posMask = AUI_MINIMIZE_POS_SMART - if paneInfo.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]: - tbStyle |= AUI_TB_HORZ_LAYOUT - - elif paneInfo.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]: - tbStyle |= AUI_TB_VERTICAL - if captMask == AUI_MINIMIZE_CAPT_SMART: - tbStyle |= AUI_TB_CLOCKWISE - else: - minimize_toolbar = minimize_toolbar.window - - elif posMask == AUI_MINIMIZE_POS_SMART: - if paneInfo.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]: - tbStyle |= AUI_TB_HORZ_LAYOUT - - elif paneInfo.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]: - tbStyle |= AUI_TB_VERTICAL - if captMask == AUI_MINIMIZE_CAPT_SMART: - tbStyle |= AUI_TB_CLOCKWISE - - elif posMask in [AUI_MINIMIZE_POS_TOP, AUI_MINIMIZE_POS_BOTTOM]: - tbStyle |= AUI_TB_HORZ_LAYOUT - if posMask == AUI_MINIMIZE_POS_TOP: - dockDirection = AUI_DOCK_TOP - else: - dockDirection = AUI_DOCK_BOTTOM - - else: - tbStyle |= AUI_TB_VERTICAL - if captMask == AUI_MINIMIZE_CAPT_SMART: - tbStyle |= AUI_TB_CLOCKWISE - if posMask == AUI_MINIMIZE_POS_LEFT: - dockDirection = AUI_DOCK_LEFT - elif posMask == AUI_MINIMIZE_POS_RIGHT: - dockDirection = AUI_DOCK_RIGHT - elif posMask == AUI_MINIMIZE_POS_BOTTOM: - dockDirection = AUI_DOCK_BOTTOM - - # Create a new toolbar - # give it the same name as the minimized pane with _min appended - - win_rect = paneInfo.window.GetScreenRect() - - if posMask != AUI_MINIMIZE_POS_TOOLBAR: - minimize_toolbar = auibar.AuiToolBar(self.GetManagedWindow(), agwStyle=tbStyle) - minimize_toolbar.Hide() - minimize_toolbar.SetToolBitmapSize(wx.Size(16, 16)) - - if paneInfo.icon and paneInfo.icon.IsOk(): - restore_bitmap = paneInfo.icon - else: - restore_bitmap = self._art._restore_bitmap - - if posMask == AUI_MINIMIZE_POS_TOOLBAR: - xsize, ysize = minimize_toolbar.GetToolBitmapSize() - if xsize != restore_bitmap.GetWidth(): - img = restore_bitmap.ConvertToImage() - img.Rescale(xsize, ysize, wx.IMAGE_QUALITY_HIGH) - restore_bitmap = img.ConvertToBitmap() - - target = None - if posMask == AUI_MINIMIZE_POS_TOOLBAR: - target = paneInfo.name - - minimize_toolbar.AddSimpleTool(ID_RESTORE_FRAME, paneInfo.caption, restore_bitmap, - _(u"Restore %s")%paneInfo.caption, target=target) - minimize_toolbar.SetAuiManager(self) - minimize_toolbar.Realize() - toolpanelname = paneInfo.name + "_min" - - if paneInfo.IsMaximized(): - paneInfo.SetFlag(paneInfo.wasMaximized, True) - - if posMask != AUI_MINIMIZE_POS_TOOLBAR: - - if dockDirection == AUI_DOCK_TOP: - self.AddPane(minimize_toolbar, AuiPaneInfo(). \ - Name(toolpanelname).Caption(paneInfo.caption). \ - ToolbarPane().Top().BottomDockable(False). \ - LeftDockable(False).RightDockable(False).DestroyOnClose()) - - elif dockDirection == AUI_DOCK_BOTTOM: - self.AddPane(minimize_toolbar, AuiPaneInfo(). \ - Name(toolpanelname).Caption(paneInfo.caption). \ - ToolbarPane().Bottom().TopDockable(False). \ - LeftDockable(False).RightDockable(False).DestroyOnClose()) - - elif dockDirection == AUI_DOCK_LEFT: - self.AddPane(minimize_toolbar, AuiPaneInfo(). \ - Name(toolpanelname).Caption(paneInfo.caption). \ - ToolbarPane().Left().TopDockable(False). \ - BottomDockable(False).RightDockable(False).DestroyOnClose()) - - elif dockDirection in [AUI_DOCK_RIGHT, AUI_DOCK_CENTER]: - self.AddPane(minimize_toolbar, AuiPaneInfo(). \ - Name(toolpanelname).Caption(paneInfo.caption). \ - ToolbarPane().Right().TopDockable(False). \ - LeftDockable(False).BottomDockable(False).DestroyOnClose()) - - arr = FindDocks(self._docks, paneInfo.dock_direction, paneInfo.dock_layer, paneInfo.dock_row) - - if arr: - dock = arr[0] - paneInfo.previousDockSize = dock.size - - paneInfo.previousDockPos = paneInfo.dock_pos - - # mark ourselves minimized - paneInfo.Minimize() - paneInfo.Show(False) - self._has_minimized = True - # last, hide the window - if paneInfo.window and paneInfo.window.IsShown(): - paneInfo.window.Show(False) - - minimize_toolbar.Show() - - if mgrUpdate: - self.Update() - if self._agwFlags & AUI_MGR_ANIMATE_FRAMES: - self.AnimateDocking(win_rect, minimize_toolbar.GetScreenRect()) - - - def OnRestoreMinimizedPane(self, event): - """ - Handles the ``EVT_AUI_PANE_MIN_RESTORE`` event for :class:`AuiManager`. - - :param `event`: an instance of :class:`AuiManagerEvent` to be processed. - """ - - self.RestoreMinimizedPane(event.pane) - - - def OnPaneDocked(self, event): - """ - Handles the ``EVT_AUI_PANE_DOCKED`` event for :class:`AuiManager`. - - :param `event`: an instance of :class:`AuiManagerEvent` to be processed. - """ - - event.Skip() - self.RemoveAutoNBCaption(event.GetPane()) - - - def CreateNotebookBase(self, panes, paneInfo): - """ - Creates an auto-notebook base from a pane, and then add that pane as a page. - - :param list `panes`: set of panes to append new notebook base pane to - :param AuiPaneInfo `paneInfo`: the pane to be converted to a new notebook. - """ - - # Create base notebook pane ... - nbid = len(self._notebooks) - - baseInfo = AuiPaneInfo() - baseInfo.SetDockPos(paneInfo).NotebookControl(nbid). \ - CloseButton(False).SetNameFromNotebookId(). \ - NotebookDockable(False).Floatable(paneInfo.IsFloatable()) - baseInfo.best_size = paneInfo.best_size - panes.append(baseInfo) - - # add original pane as tab ... - paneInfo.NotebookPage(nbid) - - - def RemoveAutoNBCaption(self, pane): - """ - Removes the caption on newly created automatic notebooks. - - :param `pane`: an instance of :class:`AuiPaneInfo` (the target notebook). - """ - - if self._agwFlags & AUI_MGR_AUTONB_NO_CAPTION == 0: - return False - - def RemoveCaption(): - """ Sub-function used to remove the pane caption on automatic notebooks. """ - - if pane.HasNotebook(): - notebook = self._notebooks[pane.notebook_id] - self.GetPane(notebook).CaptionVisible(False).PaneBorder(False) - self.Update() - - # it seems the notebook isnt created by this stage, so remove - # the caption a moment later - wx.CallAfter(RemoveCaption) - return True - - - def RestoreMinimizedPane(self, paneInfo): - """ - Restores a previously minimized pane. - - :param `paneInfo`: a :class:`AuiPaneInfo` instance for the pane to be restored. - """ - - panename = paneInfo.name - - if paneInfo.minimize_mode & AUI_MINIMIZE_POS_TOOLBAR: - pane = self.GetPane(panename) - hasTarget = True - else: - panename = panename[0:-4] - hasTarget = False - - pane = self.GetPane(panename) - pane.SetFlag(pane.needsRestore, True) - - if not pane.IsOk(): - panename = paneInfo.name - pane = self.GetPane(panename) - paneInfo = self.GetPane(panename + "_min") - if not paneInfo.IsOk(): - # Already minimized - return - - if pane.IsOk(): - if not pane.IsMinimized(): - return - - - if pane.HasFlag(pane.wasMaximized): - self.SavePreviousDockSizes(pane) - - self.ShowPane(pane.window, True) - pane.Show(True) - self._has_minimized = False - pane.SetFlag(pane.optionMinimized, False) - - if hasTarget: - targetName = pane.minimize_target - toolbarPane = self.GetPane(targetName) - toolbar = toolbarPane.window - item = toolbar.FindToolByLabel(pane.caption) - toolbar.DeleteTool(item.id) - else: - paneInfo.window.Show(False) - self.DetachPane(paneInfo.window) - paneInfo.Show(False) - paneInfo.Hide() - - self.Update() - - - def AnimateDocking(self, win_rect, pane_rect): - """ - Animates the minimization/docking of a pane a la Eclipse, using a :class:`ScreenDC` - to draw a "moving docking rectangle" on the screen. - - :param Rect `win_rect`: the original pane screen rectangle; - :param Rect `pane_rect`: the newly created toolbar/pane screen rectangle. - - :note: This functionality is not available on wxMAC as this platform doesn't have - the ability to use :class:`ScreenDC` to draw on-screen and on Windows > Vista. - """ - - if wx.Platform == "__WXMAC__": - # No wx.ScreenDC on the Mac... - return - if wx.Platform == "__WXMSW__" and wx.GetOsVersion()[1] > 5: - # No easy way to handle this on Vista... - return - - xstart, ystart = win_rect.x, win_rect.y - xend, yend = pane_rect.x, pane_rect.y - - step = self.GetAnimationStep() - - wstep = int(abs(win_rect.width - pane_rect.width)/step) - hstep = int(abs(win_rect.height - pane_rect.height)/step) - xstep = int(win_rect.x - pane_rect.x)/step - ystep = int(win_rect.y - pane_rect.y)/step - - dc = wx.ScreenDC() - dc.SetLogicalFunction(wx.INVERT) - dc.SetBrush(wx.TRANSPARENT_BRUSH) - dc.SetPen(wx.LIGHT_GREY_PEN) - - for i in xrange(int(step)): - width, height = win_rect.width - i*wstep, win_rect.height - i*hstep - x, y = xstart - i*xstep, ystart - i*ystep - new_rect = wx.Rect(x, y, width, height) - dc.DrawRoundedRectangleRect(new_rect, 3) - wx.SafeYield() - wx.MilliSleep(10) - dc.DrawRoundedRectangleRect(new_rect, 3) - - - def SmoothDock(self, paneInfo): - """ - This method implements a smooth docking effect for floating panes, similar to - what the PyQT library does with its floating windows. - - :param `paneInfo`: an instance of :class:`AuiPaneInfo`. - - :note: The smooth docking effect can only be used if you set the ``AUI_MGR_SMOOTH_DOCKING`` - style to :class:`AuiManager`. - """ - - if paneInfo.IsToolbar(): - return - - if not paneInfo.frame or self._hint_rect.IsEmpty(): - return - - hint_rect = self._hint_rect - win_rect = paneInfo.frame.GetScreenRect() - - xstart, ystart = win_rect.x, win_rect.y - xend, yend = hint_rect.x, hint_rect.y - - step = self.GetAnimationStep()/3 - - wstep = int((win_rect.width - hint_rect.width)/step) - hstep = int((win_rect.height - hint_rect.height)/step) - xstep = int((win_rect.x - hint_rect.x))/step - ystep = int((win_rect.y - hint_rect.y))/step - - for i in xrange(int(step)): - width, height = win_rect.width - i*wstep, win_rect.height - i*hstep - x, y = xstart - i*xstep, ystart - i*ystep - new_rect = wx.Rect(x, y, width, height) - paneInfo.frame.SetRect(new_rect) - wx.MilliSleep(10) - - - def SetSnapLimits(self, x, y): - """ - Modifies the snap limits used when snapping the `managed_window` to the screen - (using :meth:`SnapToScreen`) or when snapping the floating panes to one side of the - `managed_window` (using :meth:`SnapPane`). - - To change the limit after which the `managed_window` or the floating panes are - automatically stickled to the screen border (or to the `managed_window` side), - set these two variables. Default values are 15 pixels. - - :param integer `x`: the minimum horizontal distance below which the snap occurs; - :param integer `y`: the minimum vertical distance below which the snap occurs. - """ - - self._snap_limits = (x, y) - self.Snap() - - - def Snap(self): - """ - Snaps the main frame to specified position on the screen. - - :see: :meth:`SnapToScreen` - """ - - snap, hAlign, vAlign, monitor = self._is_docked - if not snap: - return - - managed_window = self.GetManagedWindow() - snap_pos = self.GetSnapPosition() - wnd_pos = managed_window.GetPosition() - snapX, snapY = self._snap_limits - - if abs(snap_pos.x - wnd_pos.x) < snapX and abs(snap_pos.y - wnd_pos.y) < snapY: - managed_window.SetPosition(snap_pos) - - - def SnapToScreen(self, snap=True, monitor=0, hAlign=wx.RIGHT, vAlign=wx.TOP): - """ - Snaps the main frame to specified position on the screen. - - :param bool `snap`: whether to snap the main frame or not; - :param integer `monitor`: the monitor display in which snapping the window; - :param integer `hAlign`: the horizontal alignment of the snapping position; - :param integer `vAlign`: the vertical alignment of the snapping position. - """ - - if not snap: - self._is_docked = (False, wx.RIGHT, wx.TOP, 0) - return - - displayCount = wx.Display.GetCount() - if monitor > displayCount: - raise Exception("Invalid monitor selected: you only have %d monitors"%displayCount) - - self._is_docked = (True, hAlign, vAlign, monitor) - self.GetManagedWindow().SetPosition(self.GetSnapPosition()) - - - def GetSnapPosition(self): - """ Returns the main frame snapping position. """ - - snap, hAlign, vAlign, monitor = self._is_docked - - display = wx.Display(monitor) - area = display.GetClientArea() - size = self.GetManagedWindow().GetSize() - - pos = wx.Point() - if hAlign == wx.LEFT: - pos.x = area.x - elif hAlign == wx.CENTER: - pos.x = area.x + (area.width - size.x)/2 - else: - pos.x = area.x + area.width - size.x - - if vAlign == wx.TOP: - pos.y = area.y - elif vAlign == wx.CENTER: - pos.y = area.y + (area.height - size.y)/2 - else: - pos.y = area.y + area.height - size.y - - return pos - - - def GetAnimationStep(self): - """ Returns the animation step speed (a float) to use in :meth:`AnimateDocking`. """ - - return self._animation_step - - - def SetAnimationStep(self, step): - """ - Sets the animation step speed (a float) to use in :meth:`AnimateDocking`. - - :param float `step`: the animation speed. - """ - - self._animation_step = float(step) - - - def RequestUserAttention(self, pane_window): - """ - Requests the user attention by intermittently highlighting the pane caption. - - :param Window `pane_window`: the window managed by the pane; - """ - - # try to find the pane - paneInfo = self.GetPane(pane_window) - if not paneInfo.IsOk(): - raise Exception("Pane window not found") - - dc = wx.ClientDC(self._frame) - - # if the frame is about to be deleted, don't bother - if not self._frame or self._frame.IsBeingDeleted(): - return - - if not self._frame.GetSizer(): - return - - for part in self._uiparts: - if part.pane == paneInfo: - self._art.RequestUserAttention(dc, self._frame, part.pane.caption, part.rect, part.pane) - self._frame.RefreshRect(part.rect, True) - break - - - def StartPreviewTimer(self, toolbar): - """ - Starts a timer for sliding in and out a minimized pane. - - :param `toolbar`: the :class:`~lib.agw.aui.auibar.AuiToolBar` containing the minimized pane tool. - """ - - toolbar_pane = self.GetPane(toolbar) - toolbar_name = toolbar_pane.name - - pane_name = toolbar_name[0:-4] - - self._sliding_pane = self.GetPane(pane_name) - self._sliding_rect = toolbar.GetScreenRect() - self._sliding_direction = toolbar_pane.dock_direction - self._sliding_frame = None - - self._preview_timer.Start(1000, wx.TIMER_ONE_SHOT) - - - def StopPreviewTimer(self): - """ Stops a timer for sliding in and out a minimized pane. """ - - if self._preview_timer.IsRunning(): - self._preview_timer.Stop() - - self.SlideOut() - self._sliding_pane = None - - - def SlideIn(self, event): - """ - Handles the ``wx.EVT_TIMER`` event for :class:`AuiManager`. - - :param `event`: a :class:`TimerEvent` to be processed. - - :note: This is used solely for sliding in and out minimized panes. - """ - - window = self._sliding_pane.window - self._sliding_frame = wx.MiniFrame(None, -1, title=_("Pane Preview"), - style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP | - wx.FRAME_NO_TASKBAR | wx.CAPTION) - window.Reparent(self._sliding_frame) - self._sliding_frame.SetSize((0, 0)) - window.Show() - self._sliding_frame.Show() - - size = window.GetBestSize() - - startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction) - - step = stopX/10 - window_size = 0 - - for i in xrange(0, stopX, step): - window_size = i - self._sliding_frame.SetDimensions(startX, startY, window_size, stopY) - self._sliding_frame.Refresh() - self._sliding_frame.Update() - wx.MilliSleep(10) - - self._sliding_frame.SetDimensions(startX, startY, stopX, stopY) - self._sliding_frame.Refresh() - self._sliding_frame.Update() - - - def SlideOut(self): - """ - Slides out a preview of a minimized pane. - - :note: This is used solely for sliding in and out minimized panes. - """ - - if not self._sliding_frame: - return - - window = self._sliding_frame.GetChildren()[0] - size = window.GetBestSize() - - startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction) - - step = stopX/10 - window_size = 0 - - for i in xrange(stopX, 0, -step): - window_size = i - self._sliding_frame.SetDimensions(startX, startY, window_size, stopY) - self._sliding_frame.Refresh() - self._sliding_frame.Update() - self._frame.RefreshRect(wx.Rect(startX+window_size, startY, step, stopY)) - self._frame.Update() - wx.MilliSleep(10) - - self._sliding_frame.SetDimensions(startX, startY, 0, stopY) - - window.Hide() - window.Reparent(self._frame) - - self._sliding_frame.Hide() - self._sliding_frame.Destroy() - self._sliding_frame = None - self._sliding_pane = None - - -class AuiManager_DCP(AuiManager): - """ - A class similar to :class:`AuiManager` but with a Dummy Center Pane (**DCP**). - The code for this class is still flickery due to the call to :func:`CallAfter` - and the double-update call. - """ - - def __init__(self, *args, **keys): - """ See :meth:`AuiManager.__init__` for the class construction. """ - - AuiManager.__init__(self, *args, **keys) - self.hasDummyPane = False - - - def _createDummyPane(self): - """ Creates a Dummy Center Pane (**DCP**). """ - - if self.hasDummyPane: - return - - self.hasDummyPane = True - dummy = wx.Panel(self.GetManagedWindow()) - info = AuiPaneInfo().CenterPane().NotebookDockable(True).Name('dummyCenterPane').DestroyOnClose(True) - self.AddPane(dummy, info) - - - def _destroyDummyPane(self): - """ Destroys the Dummy Center Pane (**DCP**). """ - - if not self.hasDummyPane: - return - - self.hasDummyPane = False - self.ClosePane(self.GetPane('dummyCenterPane')) - - - def Update(self): - """ - This method is called after any number of changes are made to any of the - managed panes. :meth:`Update` must be invoked after :meth:`AuiManager.AddPane` or - :meth:`AuiManager.InsertPane` are called in order to "realize" or "commit" the changes. - - In addition, any number of changes may be made to :class:`AuiManager` structures - (retrieved with :meth:`AuiManager.GetPane`), but to realize the changes, - :meth:`Update` must be called. This construction allows pane flicker to - be avoided by updating the whole layout at one time. - """ - AuiManager.Update(self) - - # check if there's already a center pane (except our dummy pane) - dummyCenterPane = self.GetPane('dummyCenterPane') - haveCenterPane = any((pane != dummyCenterPane) and (pane.dock_direction == AUI_DOCK_CENTER) and - not pane.IsFloating() and pane.IsShown() for pane in self.GetAllPanes()) - if haveCenterPane: - if self.hasDummyPane: - # there's our dummy pane and also another center pane, therefor let's remove our dummy - def do(): - self._destroyDummyPane() - self.Update() - wx.CallAfter(do) - else: - # if we get here, there's no center pane, create our dummy - if not self.hasDummyPane: - self._createDummyPane() - - diff --git a/enaml/wx/wx_upstream/aui/tabart.py b/enaml/wx/wx_upstream/aui/tabart.py deleted file mode 100644 index f6e1ff45b..000000000 --- a/enaml/wx/wx_upstream/aui/tabart.py +++ /dev/null @@ -1,2784 +0,0 @@ -""" -Tab art provider code - a tab provider provides all drawing functionality to -the :class:`~lib.agw.aui.auibook.AuiNotebook`. This allows the -:class:`~lib.agw.aui.auibook.AuiNotebook` to have a plugable look-and-feel. - -By default, a :class:`~lib.agw.aui.auibook.AuiNotebook` uses an instance of this class -called :class:`AuiDefaultTabArt` which provides bitmap art and a colour scheme that is -adapted to the major platforms' look. You can either derive from that class to alter its -behaviour or write a completely new tab art class. -Call :meth:`AuiNotebook.SetArtProvider() ` -to make use this new tab art. -""" - -__author__ = "Andrea Gavana " -__date__ = "31 March 2009" - - -import wx - -if wx.Platform == '__WXMAC__': - import Carbon.Appearance - -from aui_utilities import BitmapFromBits, StepColour, IndentPressedBitmap, ChopText -from aui_utilities import GetBaseColour, DrawMACCloseButton, LightColour, TakeScreenShot -from aui_utilities import CopyAttributes - -from aui_constants import * - - -# -- GUI helper classes and functions -- -class AuiCommandCapture(wx.PyEvtHandler): - """ A class to handle the dropdown window menu. """ - - def __init__(self): - """ Default class constructor. """ - - wx.PyEvtHandler.__init__(self) - self._last_id = 0 - - - def GetCommandId(self): - """ Returns the event command identifier. """ - - return self._last_id - - - def ProcessEvent(self, event): - """ - Processes an event, searching event tables and calling zero or more suitable - event handler function(s). - - :param `event`: the event to process. - - :note: Normally, your application would not call this function: it is called - in the wxPython implementation to dispatch incoming user interface events - to the framework (and application). - However, you might need to call it if implementing new functionality (such as - a new control) where you define new event types, as opposed to allowing the - user to override functions. - - An instance where you might actually override the :meth:`ProcessEvent` function is where - you want to direct event processing to event handlers not normally noticed by - wxPython. For example, in the document/view architecture, documents and views - are potential event handlers. When an event reaches a frame, :meth:`ProcessEvent` will - need to be called on the associated document and view in case event handler - functions are associated with these objects. - - The normal order of event table searching is as follows: - - 1. If the object is disabled (via a call to :meth:`EvtHandler.SetEvtHandlerEnabled`) the function - skips to step (6). - 2. If the object is a :class:`Window`, :meth:`ProcessEvent` is recursively called on the window's - :class:`Validator`. If this returns ``True``, the function exits. - 3. wxWidgets `SearchEventTable` is called for this event handler. If this fails, the - base class table is tried, and so on until no more tables exist or an appropriate - function was found, in which case the function exits. - 4. The search is applied down the entire chain of event handlers (usually the chain - has a length of one). If this succeeds, the function exits. - 5. If the object is a :class:`Window` and the event is a :class:`CommandEvent`, :meth:`ProcessEvent` is - recursively applied to the parent window's event handler. If this returns ``True``, - the function exits. - 6. Finally, :meth:`ProcessEvent` is called on the :class:`App` object. - """ - - if event.GetEventType() == wx.wxEVT_COMMAND_MENU_SELECTED: - self._last_id = event.GetId() - return True - - if self.GetNextHandler(): - return self.GetNextHandler().ProcessEvent(event) - - return False - - -class AuiDefaultTabArt(object): - """ - Tab art provider code - a tab provider provides all drawing functionality to the :class:`~lib.agw.aui.auibook.AuiNotebook`. - This allows the :class:`~lib.agw.aui.auibook.AuiNotebook` to have a plugable look-and-feel. - - By default, a :class:`~lib.agw.aui.auibook.AuiNotebook` uses an instance of this class called - :class:`AuiDefaultTabArt` which provides bitmap art and a colour scheme that is adapted to the major platforms' - look. You can either derive from that class to alter its behaviour or write a - completely new tab art class. Call :meth:`AuiNotebook.SetArtProvider() ` to make use this - new tab art. - """ - - def __init__(self): - """ Default class constructor. """ - - self._normal_font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) - self._selected_font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) - self._selected_font.SetWeight(wx.BOLD) - self._measuring_font = self._selected_font - - self._fixed_tab_width = 100 - self._tab_ctrl_height = 0 - self._buttonRect = wx.Rect() - - self.SetDefaultColours() - - if wx.Platform == "__WXMAC__": - bmp_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW) - self._active_close_bmp = DrawMACCloseButton(bmp_colour) - self._disabled_close_bmp = DrawMACCloseButton(wx.Colour(128, 128, 128)) - else: - self._active_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.BLACK) - self._disabled_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.Colour(128, 128, 128)) - - self._hover_close_bmp = self._active_close_bmp - self._pressed_close_bmp = self._active_close_bmp - - self._active_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.BLACK) - self._disabled_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.Colour(128, 128, 128)) - - self._active_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.BLACK) - self._disabled_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.Colour(128, 128, 128)) - - self._active_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.BLACK) - self._disabled_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.Colour(128, 128, 128)) - - if wx.Platform == "__WXMAC__": - # Get proper highlight colour for focus rectangle from the - # current Mac theme. kThemeBrushFocusHighlight is - # available on Mac OS 8.5 and higher - if hasattr(wx, 'MacThemeColour'): - c = wx.MacThemeColour(Carbon.Appearance.kThemeBrushFocusHighlight) - else: - brush = wx.Brush(wx.BLACK) - brush.MacSetTheme(Carbon.Appearance.kThemeBrushFocusHighlight) - c = brush.GetColour() - self._focusPen = wx.Pen(c, 2, wx.SOLID) - else: - self._focusPen = wx.Pen(wx.BLACK, 1, wx.USER_DASH) - self._focusPen.SetDashes([1, 1]) - self._focusPen.SetCap(wx.CAP_BUTT) - - - def SetBaseColour(self, base_colour): - """ - Sets a new base colour. - - :param `base_colour`: an instance of :class:`Colour`. - """ - - self._base_colour = base_colour - self._base_colour_pen = wx.Pen(self._base_colour) - self._base_colour_brush = wx.Brush(self._base_colour) - - - def SetDefaultColours(self, base_colour=None): - """ - Sets the default colours, which are calculated from the given base colour. - - :param `base_colour`: an instance of :class:`Colour`. If defaulted to ``None``, a colour - is generated accordingly to the platform and theme. - """ - - if base_colour is None: - base_colour = GetBaseColour() - - self.SetBaseColour( base_colour ) - self._border_colour = StepColour(base_colour, 75) - self._border_pen = wx.Pen(self._border_colour) - - self._background_top_colour = StepColour(self._base_colour, 90) - self._background_bottom_colour = StepColour(self._base_colour, 170) - - self._tab_top_colour = self._base_colour - self._tab_bottom_colour = wx.WHITE - self._tab_gradient_highlight_colour = wx.WHITE - - self._tab_inactive_top_colour = self._base_colour - self._tab_inactive_bottom_colour = StepColour(self._tab_inactive_top_colour, 160) - - self._tab_text_colour = lambda page: page.text_colour - self._tab_disabled_text_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT) - - - def Clone(self): - """ Clones the art object. """ - - art = type(self)() - art.SetNormalFont(self.GetNormalFont()) - art.SetSelectedFont(self.GetSelectedFont()) - art.SetMeasuringFont(self.GetMeasuringFont()) - - art = CopyAttributes(art, self) - return art - - - def SetAGWFlags(self, agwFlags): - """ - Sets the tab art flags. - - :param integer `agwFlags`: a combination of the following values: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook - ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet. - ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet. - ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook - ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab - ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging - ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control - ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width - ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed - ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available - ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar - ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab - ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs - ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close :class:`~lib.agw.aui.auibook.AuiNotebook` tabs by mouse middle button click - ``AUI_NB_SUB_NOTEBOOK`` This style is used by :class:`~lib.agw.aui.framemanager.AuiManager` to create automatic AuiNotebooks - ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present - ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows - ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items - ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser) - ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less - full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages - ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default) - ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs - ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle - ==================================== ================================== - - """ - - self._agwFlags = agwFlags - - - def GetAGWFlags(self): - """ - Returns the tab art flags. - - :see: :meth:`~AuiDefaultTabArt.SetAGWFlags` for a list of possible return values. - """ - - return self._agwFlags - - - def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth): - """ - Sets the tab sizing information. - - :param Size `tab_ctrl_size`: the size of the tab control area; - :param integer `tab_count`: the number of tabs; - :param tuple `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths - to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active. - """ - - self._fixed_tab_width = 100 - minTabWidth, maxTabWidth = minMaxTabWidth - - tot_width = tab_ctrl_size.x - self.GetIndentSize() - 4 - agwFlags = self.GetAGWFlags() - - if agwFlags & AUI_NB_CLOSE_BUTTON: - tot_width -= self._active_close_bmp.GetWidth() - if agwFlags & AUI_NB_WINDOWLIST_BUTTON: - tot_width -= self._active_windowlist_bmp.GetWidth() - - if tab_count > 0: - self._fixed_tab_width = tot_width/tab_count - - if self._fixed_tab_width < 100: - self._fixed_tab_width = 100 - - if self._fixed_tab_width > tot_width/2: - self._fixed_tab_width = tot_width/2 - - if self._fixed_tab_width > 220: - self._fixed_tab_width = 220 - - if minTabWidth > -1: - self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth) - if maxTabWidth > -1: - self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth) - - self._tab_ctrl_height = tab_ctrl_size.y - - - def DrawBackground(self, dc, wnd, rect): - """ - Draws the tab area background. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param Rect `rect`: the tab control rectangle. - """ - - self._buttonRect = wx.Rect() - - # draw background - agwFlags = self.GetAGWFlags() - if agwFlags & AUI_NB_BOTTOM: - r = wx.Rect(rect.x, rect.y, rect.width+2, rect.height) - - # TODO: else if (agwFlags & AUI_NB_LEFT) - # TODO: else if (agwFlags & AUI_NB_RIGHT) - else: #for AUI_NB_TOP - r = wx.Rect(rect.x, rect.y, rect.width+2, rect.height-3) - - dc.GradientFillLinear(r, self._background_top_colour, self._background_bottom_colour, wx.SOUTH) - - # draw base lines - - dc.SetPen(self._border_pen) - y = rect.GetHeight() - w = rect.GetWidth() - - if agwFlags & AUI_NB_BOTTOM: - dc.SetBrush(wx.Brush(self._background_bottom_colour)) - dc.DrawRectangle(-1, 0, w+2, 4) - - # TODO: else if (agwFlags & AUI_NB_LEFT) - # TODO: else if (agwFlags & AUI_NB_RIGHT) - - else: # for AUI_NB_TOP - dc.SetBrush(self._base_colour_brush) - dc.DrawRectangle(-1, y-4, w+2, 4) - - - def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False): - """ - Draws a single tab. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param `page`: the tab control page associated with the tab; - :param Rect `in_rect`: rectangle the tab should be confined to; - :param integer `close_button_state`: the state of the close button on the tab; - :param bool `paint_control`: whether to draw the control inside a tab (if any) on a :class:`MemoryDC`. - """ - - # if the caption is empty, measure some temporary text - caption = page.caption - if not caption: - caption = "Xj" - - dc.SetFont(self._selected_font) - selected_textx, selected_texty, dummy = dc.GetMultiLineTextExtent(caption) - - dc.SetFont(self._normal_font) - normal_textx, normal_texty, dummy = dc.GetMultiLineTextExtent(caption) - - control = page.control - - # figure out the size of the tab - tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, - page.active, close_button_state, control) - - tab_height = self._tab_ctrl_height - 3 - tab_width = tab_size[0] - tab_x = in_rect.x - tab_y = in_rect.y + in_rect.height - tab_height - - caption = page.caption - - # select pen, brush and font for the tab to be drawn - - if page.active: - - dc.SetFont(self._selected_font) - textx, texty = selected_textx, selected_texty - - else: - - dc.SetFont(self._normal_font) - textx, texty = normal_textx, normal_texty - - if not page.enabled: - dc.SetTextForeground(self._tab_disabled_text_colour) - pagebitmap = page.dis_bitmap - else: - dc.SetTextForeground(self._tab_text_colour(page)) - pagebitmap = page.bitmap - - # create points that will make the tab outline - - clip_width = tab_width - if tab_x + clip_width > in_rect.x + in_rect.width: - clip_width = in_rect.x + in_rect.width - tab_x - - # since the above code above doesn't play well with WXDFB or WXCOCOA, - # we'll just use a rectangle for the clipping region for now -- - dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3) - - border_points = [wx.Point() for i in xrange(6)] - agwFlags = self.GetAGWFlags() - - if agwFlags & AUI_NB_BOTTOM: - - border_points[0] = wx.Point(tab_x, tab_y) - border_points[1] = wx.Point(tab_x, tab_y+tab_height-6) - border_points[2] = wx.Point(tab_x+2, tab_y+tab_height-4) - border_points[3] = wx.Point(tab_x+tab_width-2, tab_y+tab_height-4) - border_points[4] = wx.Point(tab_x+tab_width, tab_y+tab_height-6) - border_points[5] = wx.Point(tab_x+tab_width, tab_y) - - else: #if (agwFlags & AUI_NB_TOP) - - border_points[0] = wx.Point(tab_x, tab_y+tab_height-4) - border_points[1] = wx.Point(tab_x, tab_y+2) - border_points[2] = wx.Point(tab_x+2, tab_y) - border_points[3] = wx.Point(tab_x+tab_width-2, tab_y) - border_points[4] = wx.Point(tab_x+tab_width, tab_y+2) - border_points[5] = wx.Point(tab_x+tab_width, tab_y+tab_height-4) - - # TODO: else if (agwFlags & AUI_NB_LEFT) - # TODO: else if (agwFlags & AUI_NB_RIGHT) - - drawn_tab_yoff = border_points[1].y - drawn_tab_height = border_points[0].y - border_points[1].y - - if page.active: - - # draw active tab - - # draw base background colour - r = wx.Rect(tab_x, tab_y, tab_width, tab_height) - dc.SetPen(self._base_colour_pen) - dc.SetBrush(self._base_colour_brush) - dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4) - - # this white helps fill out the gradient at the top of the tab - dc.SetPen( wx.Pen(self._tab_gradient_highlight_colour) ) - dc.SetBrush( wx.Brush(self._tab_gradient_highlight_colour) ) - dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4) - - # these two points help the rounded corners appear more antialiased - dc.SetPen(self._base_colour_pen) - dc.DrawPoint(r.x+2, r.y+1) - dc.DrawPoint(r.x+r.width-2, r.y+1) - - # set rectangle down a bit for gradient drawing - r.SetHeight(r.GetHeight()/2) - r.x += 2 - r.width -= 2 - r.y += r.height - r.y -= 2 - - # draw gradient background - top_colour = self._tab_bottom_colour - bottom_colour = self._tab_top_colour - dc.GradientFillLinear(r, bottom_colour, top_colour, wx.NORTH) - - else: - - # draw inactive tab - - r = wx.Rect(tab_x, tab_y+1, tab_width, tab_height-3) - - # start the gradent up a bit and leave the inside border inset - # by a pixel for a 3D look. Only the top half of the inactive - # tab will have a slight gradient - r.x += 3 - r.y += 1 - r.width -= 4 - r.height /= 2 - r.height -= 1 - - # -- draw top gradient fill for glossy look - top_colour = self._tab_inactive_top_colour - bottom_colour = self._tab_inactive_bottom_colour - dc.GradientFillLinear(r, bottom_colour, top_colour, wx.NORTH) - - r.y += r.height - r.y -= 1 - - # -- draw bottom fill for glossy look - top_colour = self._tab_inactive_bottom_colour - bottom_colour = self._tab_inactive_bottom_colour - dc.GradientFillLinear(r, top_colour, bottom_colour, wx.SOUTH) - - # draw tab outline - dc.SetPen(self._border_pen) - dc.SetBrush(wx.TRANSPARENT_BRUSH) - dc.DrawPolygon(border_points) - - # there are two horizontal grey lines at the bottom of the tab control, - # this gets rid of the top one of those lines in the tab control - if page.active: - - if agwFlags & AUI_NB_BOTTOM: - dc.SetPen(wx.Pen(self._background_bottom_colour)) - - # TODO: else if (agwFlags & AUI_NB_LEFT) - # TODO: else if (agwFlags & AUI_NB_RIGHT) - else: # for AUI_NB_TOP - dc.SetPen(self._base_colour_pen) - - dc.DrawLine(border_points[0].x+1, - border_points[0].y, - border_points[5].x, - border_points[5].y) - - text_offset = tab_x + 8 - close_button_width = 0 - - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - close_button_width = self._active_close_bmp.GetWidth() - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - text_offset += close_button_width - 5 - - bitmap_offset = 0 - - if pagebitmap.IsOk(): - - bitmap_offset = tab_x + 8 - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width: - bitmap_offset += close_button_width - 5 - - # draw bitmap - dc.DrawBitmap(pagebitmap, - bitmap_offset, - drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2), - True) - - text_offset = bitmap_offset + pagebitmap.GetWidth() - text_offset += 3 # bitmap padding - - else: - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width: - text_offset = tab_x + 8 - - draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width) - - ypos = drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1 - - offset_focus = text_offset - if control is not None: - if control.GetPosition() != wx.Point(text_offset+1, ypos): - control.SetPosition(wx.Point(text_offset+1, ypos)) - - if not control.IsShown(): - control.Show() - - if paint_control: - bmp = TakeScreenShot(control.GetScreenRect()) - dc.DrawBitmap(bmp, text_offset+1, ypos, True) - - controlW, controlH = control.GetSize() - text_offset += controlW + 4 - textx += controlW + 4 - - # draw tab text - rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text) - dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty)) - - # draw focus rectangle - if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0: - self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff, drawn_tab_height, rectx, recty) - - out_button_rect = wx.Rect() - - # draw close button if necessary - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - - bmp = self._disabled_close_bmp - - if close_button_state == AUI_BUTTON_STATE_HOVER: - bmp = self._hover_close_bmp - elif close_button_state == AUI_BUTTON_STATE_PRESSED: - bmp = self._pressed_close_bmp - - shift = (agwFlags & AUI_NB_BOTTOM and [1] or [0])[0] - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - rect = wx.Rect(tab_x + 4, tab_y + (tab_height - bmp.GetHeight())/2 - shift, - close_button_width, tab_height) - else: - rect = wx.Rect(tab_x + tab_width - close_button_width - 1, - tab_y + (tab_height - bmp.GetHeight())/2 - shift, - close_button_width, tab_height) - - rect = IndentPressedBitmap(rect, close_button_state) - dc.DrawBitmap(bmp, rect.x, rect.y, True) - - out_button_rect = rect - - out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height) - - dc.DestroyClippingRegion() - - return out_tab_rect, out_button_rect, x_extent - - - def SetCustomButton(self, bitmap_id, button_state, bmp): - """ - Sets a custom bitmap for the close, left, right and window list buttons. - - :param integer `bitmap_id`: the button identifier; - :param integer `button_state`: the button state; - :param Bitmap `bmp`: the custom bitmap to use for the button. - """ - - if bitmap_id == AUI_BUTTON_CLOSE: - if button_state == AUI_BUTTON_STATE_NORMAL: - self._active_close_bmp = bmp - self._hover_close_bmp = self._active_close_bmp - self._pressed_close_bmp = self._active_close_bmp - self._disabled_close_bmp = self._active_close_bmp - - elif button_state == AUI_BUTTON_STATE_HOVER: - self._hover_close_bmp = bmp - elif button_state == AUI_BUTTON_STATE_PRESSED: - self._pressed_close_bmp = bmp - else: - self._disabled_close_bmp = bmp - - elif bitmap_id == AUI_BUTTON_LEFT: - if button_state & AUI_BUTTON_STATE_DISABLED: - self._disabled_left_bmp = bmp - else: - self._active_left_bmp = bmp - - elif bitmap_id == AUI_BUTTON_RIGHT: - if button_state & AUI_BUTTON_STATE_DISABLED: - self._disabled_right_bmp = bmp - else: - self._active_right_bmp = bmp - - elif bitmap_id == AUI_BUTTON_WINDOWLIST: - if button_state & AUI_BUTTON_STATE_DISABLED: - self._disabled_windowlist_bmp = bmp - else: - self._active_windowlist_bmp = bmp - - - def GetIndentSize(self): - """ Returns the tabs indent size. """ - - return 5 - - - def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None): - """ - Returns the tab size for the given caption, bitmap and button state. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param string `caption`: the tab text caption; - :param Bitmap `bitmap`: the bitmap displayed on the tab; - :param bool `active`: whether the tab is selected or not; - :param integer `close_button_state`: the state of the close button on the tab; - :param Window `control`: a :class:`Window` instance inside a tab (or ``None``). - """ - - dc.SetFont(self._measuring_font) - measured_textx, measured_texty, dummy = dc.GetMultiLineTextExtent(caption) - - # add padding around the text - tab_width = measured_textx - tab_height = measured_texty - - # if the close button is showing, add space for it - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - tab_width += self._active_close_bmp.GetWidth() + 3 - - # if there's a bitmap, add space for it - if bitmap.IsOk(): - tab_width += bitmap.GetWidth() - tab_width += 3 # right side bitmap padding - tab_height = max(tab_height, bitmap.GetHeight()) - - # add padding - tab_width += 16 - tab_height += 10 - - agwFlags = self.GetAGWFlags() - if agwFlags & AUI_NB_TAB_FIXED_WIDTH: - tab_width = self._fixed_tab_width - - if control is not None: - tab_width += control.GetSize().GetWidth() + 4 - - x_extent = tab_width - - return (tab_width, tab_height), x_extent - - - def DrawButton(self, dc, wnd, in_rect, button, orientation): - """ - Draws a button on the tab or on the tab area, depending on the button identifier. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param Rect `in_rect`: rectangle the tab should be confined to; - :param `button`: an instance of the button class; - :param integer `orientation`: the tab orientation. - """ - - bitmap_id, button_state = button.id, button.cur_state - - if bitmap_id == AUI_BUTTON_CLOSE: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = self._disabled_close_bmp - elif button_state & AUI_BUTTON_STATE_HOVER: - bmp = self._hover_close_bmp - elif button_state & AUI_BUTTON_STATE_PRESSED: - bmp = self._pressed_close_bmp - else: - bmp = self._active_close_bmp - - elif bitmap_id == AUI_BUTTON_LEFT: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = self._disabled_left_bmp - else: - bmp = self._active_left_bmp - - elif bitmap_id == AUI_BUTTON_RIGHT: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = self._disabled_right_bmp - else: - bmp = self._active_right_bmp - - elif bitmap_id == AUI_BUTTON_WINDOWLIST: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = self._disabled_windowlist_bmp - else: - bmp = self._active_windowlist_bmp - - else: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = button.dis_bitmap - else: - bmp = button.bitmap - - if not bmp.IsOk(): - return - - rect = wx.Rect(*in_rect) - - if orientation == wx.LEFT: - - rect.SetX(in_rect.x) - rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2)) - rect.SetWidth(bmp.GetWidth()) - rect.SetHeight(bmp.GetHeight()) - - else: - - rect = wx.Rect(in_rect.x + in_rect.width - bmp.GetWidth(), - ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2), - bmp.GetWidth(), bmp.GetHeight()) - - rect = IndentPressedBitmap(rect, button_state) - dc.DrawBitmap(bmp, rect.x, rect.y, True) - - out_rect = rect - - if bitmap_id == AUI_BUTTON_RIGHT: - self._buttonRect = wx.Rect(rect.x, rect.y, 30, rect.height) - - return out_rect - - - def DrawFocusRectangle(self, dc, page, wnd, draw_text, text_offset, bitmap_offset, drawn_tab_yoff, drawn_tab_height, textx, texty): - """ - Draws the focus rectangle on a tab. - - :param `dc`: a :class:`DC` device context; - :param `page`: the page associated with the tab; - :param `wnd`: a :class:`Window` instance object; - :param string `draw_text`: the text that has been drawn on the tab; - :param integer `text_offset`: the text offset on the tab; - :param integer `bitmap_offset`: the bitmap offset on the tab; - :param integer `drawn_tab_yoff`: the y offset of the tab text; - :param integer `drawn_tab_height`: the height of the tab; - :param integer `textx`: the x text extent; - :param integer `texty`: the y text extent. - """ - - if self.GetAGWFlags() & AUI_NB_NO_TAB_FOCUS: - return - - if page.active and wx.Window.FindFocus() == wnd: - - focusRectText = wx.Rect(text_offset, (drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2)), - textx, texty) - - if page.bitmap.IsOk(): - focusRectBitmap = wx.Rect(bitmap_offset, drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2), - page.bitmap.GetWidth(), page.bitmap.GetHeight()) - - if page.bitmap.IsOk() and draw_text == "": - focusRect = wx.Rect(*focusRectBitmap) - elif not page.bitmap.IsOk() and draw_text != "": - focusRect = wx.Rect(*focusRectText) - elif page.bitmap.IsOk() and draw_text != "": - focusRect = focusRectText.Union(focusRectBitmap) - - focusRect.Inflate(2, 2) - - dc.SetBrush(wx.TRANSPARENT_BRUSH) - dc.SetPen(self._focusPen) - dc.DrawRoundedRectangleRect(focusRect, 2) - - - def GetBestTabCtrlSize(self, wnd, pages, required_bmp_size): - """ - Returns the best tab control size. - - :param `wnd`: a :class:`Window` instance object; - :param list `pages`: the pages associated with the tabs; - :param Size `required_bmp_size`: the size of the bitmap on the tabs. - """ - - dc = wx.ClientDC(wnd) - dc.SetFont(self._measuring_font) - - # sometimes a standard bitmap size needs to be enforced, especially - # if some tabs have bitmaps and others don't. This is important because - # it prevents the tab control from resizing when tabs are added. - - measure_bmp = wx.NullBitmap - - if required_bmp_size.IsFullySpecified(): - measure_bmp = wx.EmptyBitmap(required_bmp_size.x, - required_bmp_size.y) - - max_y = 0 - - for page in pages: - - if measure_bmp.IsOk(): - bmp = measure_bmp - else: - bmp = page.bitmap - - # we don't use the caption text because we don't - # want tab heights to be different in the case - # of a very short piece of text on one tab and a very - # tall piece of text on another tab - s, x_ext = self.GetTabSize(dc, wnd, page.caption, bmp, True, AUI_BUTTON_STATE_HIDDEN, None) - max_y = max(max_y, s[1]) - - if page.control: - controlW, controlH = page.control.GetSize() - max_y = max(max_y, controlH+4) - - return max_y + 2 - - - def SetNormalFont(self, font): - """ - Sets the normal font for drawing tab labels. - - :param Font `font`: the new font to use to draw tab labels in their normal, un-selected state. - """ - - self._normal_font = font - - - def SetSelectedFont(self, font): - """ - Sets the selected tab font for drawing tab labels. - - :param Font `font`: the new font to use to draw tab labels in their selected state. - """ - - self._selected_font = font - - - def SetMeasuringFont(self, font): - """ - Sets the font for calculating text measurements. - - :param Font `font`: the new font to use to measure tab labels text extents. - """ - - self._measuring_font = font - - - def GetNormalFont(self): - """ Returns the normal font for drawing tab labels. """ - - return self._normal_font - - - def GetSelectedFont(self): - """ Returns the selected tab font for drawing tab labels. """ - - return self._selected_font - - - def GetMeasuringFont(self): - """ Returns the font for calculating text measurements. """ - - return self._measuring_font - - - def ShowDropDown(self, wnd, pages, active_idx): - """ - Shows the drop-down window menu on the tab area. - - :param `wnd`: a :class:`Window` derived window instance; - :param list `pages`: the pages associated with the tabs; - :param integer `active_idx`: the active tab index. - """ - - useImages = self.GetAGWFlags() & AUI_NB_USE_IMAGES_DROPDOWN - menuPopup = wx.Menu() - - longest = 0 - for i, page in enumerate(pages): - - caption = page.caption - - # if there is no caption, make it a space. This will prevent - # an assert in the menu code. - if caption == "": - caption = " " - - # Save longest caption width for calculating menu width with - width = wnd.GetTextExtent(caption)[0] - if width > longest: - longest = width - - if useImages: - menuItem = wx.MenuItem(menuPopup, 1000+i, caption) - if page.bitmap: - menuItem.SetBitmap(page.bitmap) - - menuPopup.AppendItem(menuItem) - - else: - - menuPopup.AppendCheckItem(1000+i, caption) - - menuPopup.Enable(1000+i, page.enabled) - - if active_idx != -1 and not useImages: - - menuPopup.Check(1000+active_idx, True) - - # find out the screen coordinate at the bottom of the tab ctrl - cli_rect = wnd.GetClientRect() - - # Calculate the approximate size of the popupmenu for setting the - # position of the menu when its shown. - # Account for extra padding on left/right of text on mac menus - if wx.Platform in ['__WXMAC__', '__WXMSW__']: - longest += 32 - - # Bitmap/Checkmark width + padding - longest += 20 - - if self.GetAGWFlags() & AUI_NB_CLOSE_BUTTON: - longest += 16 - - pt = wx.Point(cli_rect.x + cli_rect.GetWidth() - longest, - cli_rect.y + cli_rect.height) - - cc = AuiCommandCapture() - wnd.PushEventHandler(cc) - wnd.PopupMenu(menuPopup, pt) - command = cc.GetCommandId() - wnd.PopEventHandler(True) - - if command >= 1000: - return command - 1000 - - return -1 - - -class AuiSimpleTabArt(object): - """ A simple-looking implementation of a tab art. """ - - def __init__(self): - """ Default class constructor. """ - - self._normal_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) - self._selected_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) - self._selected_font.SetWeight(wx.BOLD) - self._measuring_font = self._selected_font - - self._agwFlags = 0 - self._fixed_tab_width = 100 - - base_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE) - - background_colour = base_colour - normaltab_colour = base_colour - selectedtab_colour = wx.WHITE - - self._bkbrush = wx.Brush(background_colour) - self._normal_bkbrush = wx.Brush(normaltab_colour) - self._normal_bkpen = wx.Pen(normaltab_colour) - self._selected_bkbrush = wx.Brush(selectedtab_colour) - self._selected_bkpen = wx.Pen(selectedtab_colour) - - self._active_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.BLACK) - self._disabled_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.Colour(128, 128, 128)) - - self._active_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.BLACK) - self._disabled_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.Colour(128, 128, 128)) - - self._active_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.BLACK) - self._disabled_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.Colour(128, 128, 128)) - - self._active_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.BLACK) - self._disabled_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.Colour(128, 128, 128)) - - - def Clone(self): - """ Clones the art object. """ - - art = type(self)() - art.SetNormalFont(self.GetNormalFont()) - art.SetSelectedFont(self.GetSelectedFont()) - art.SetMeasuringFont(self.GetMeasuringFont()) - - art = CopyAttributes(art, self) - return art - - - def SetAGWFlags(self, agwFlags): - """ - Sets the tab art flags. - - :param integer `agwFlags`: a combination of the following values: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook - ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet. - ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet. - ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook - ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab - ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging - ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control - ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width - ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed - ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available - ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar - ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab - ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs - ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close :class:`~lib.agw.aui.auibook.AuiNotebook` tabs by mouse middle button click - ``AUI_NB_SUB_NOTEBOOK`` This style is used by :class:`~lib.agw.aui.framemanager.AuiManager` to create automatic AuiNotebooks - ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present - ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows - ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items - ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser) - ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less full - screen, tabs cannot be dragged far enough outside of the notebook to become floating pages - ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default) - ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs - ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle - ==================================== ================================== - - """ - - self._agwFlags = agwFlags - - - def GetAGWFlags(self): - """ - Returns the tab art flags. - - :see: :meth:`~AuiSimpleTabArt.SetAGWFlags` for a list of possible return values. - """ - - return self._agwFlags - - - def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth): - """ - Sets the tab sizing information. - - :param Size `tab_ctrl_size`: the size of the tab control area; - :param integer `tab_count`: the number of tabs; - :param tuple `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths - to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active. - """ - - self._fixed_tab_width = 100 - minTabWidth, maxTabWidth = minMaxTabWidth - - tot_width = tab_ctrl_size.x - self.GetIndentSize() - 4 - - if self._agwFlags & AUI_NB_CLOSE_BUTTON: - tot_width -= self._active_close_bmp.GetWidth() - if self._agwFlags & AUI_NB_WINDOWLIST_BUTTON: - tot_width -= self._active_windowlist_bmp.GetWidth() - - if tab_count > 0: - self._fixed_tab_width = tot_width/tab_count - - if self._fixed_tab_width < 100: - self._fixed_tab_width = 100 - - if self._fixed_tab_width > tot_width/2: - self._fixed_tab_width = tot_width/2 - - if self._fixed_tab_width > 220: - self._fixed_tab_width = 220 - - if minTabWidth > -1: - self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth) - if maxTabWidth > -1: - self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth) - - self._tab_ctrl_height = tab_ctrl_size.y - - - def DrawBackground(self, dc, wnd, rect): - """ - Draws the tab area background. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param Rect `rect`: the tab control rectangle. - """ - - # draw background - dc.SetBrush(self._bkbrush) - dc.SetPen(wx.TRANSPARENT_PEN) - dc.DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2) - - # draw base line - dc.SetPen(wx.GREY_PEN) - dc.DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1) - - - def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False): - """ - Draws a single tab. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param `page`: the tab control page associated with the tab; - :param Rect `in_rect`: rectangle the tab should be confined to; - :param integer `close_button_state`: the state of the close button on the tab; - :param bool `paint_control`: whether to draw the control inside a tab (if any) on a :class:`MemoryDC`. - """ - - # if the caption is empty, measure some temporary text - caption = page.caption - if caption == "": - caption = "Xj" - - agwFlags = self.GetAGWFlags() - - dc.SetFont(self._selected_font) - selected_textx, selected_texty, dummy = dc.GetMultiLineTextExtent(caption) - - dc.SetFont(self._normal_font) - normal_textx, normal_texty, dummy = dc.GetMultiLineTextExtent(caption) - - control = page.control - - # figure out the size of the tab - tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, - page.active, close_button_state, control) - - tab_height = tab_size[1] - tab_width = tab_size[0] - tab_x = in_rect.x - tab_y = in_rect.y + in_rect.height - tab_height - - caption = page.caption - # select pen, brush and font for the tab to be drawn - - if page.active: - - dc.SetPen(self._selected_bkpen) - dc.SetBrush(self._selected_bkbrush) - dc.SetFont(self._selected_font) - textx = selected_textx - texty = selected_texty - - else: - - dc.SetPen(self._normal_bkpen) - dc.SetBrush(self._normal_bkbrush) - dc.SetFont(self._normal_font) - textx = normal_textx - texty = normal_texty - - if not page.enabled: - dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) - else: - dc.SetTextForeground(page.text_colour) - - # -- draw line -- - - points = [wx.Point() for i in xrange(7)] - points[0].x = tab_x - points[0].y = tab_y + tab_height - 1 - points[1].x = tab_x + tab_height - 3 - points[1].y = tab_y + 2 - points[2].x = tab_x + tab_height + 3 - points[2].y = tab_y - points[3].x = tab_x + tab_width - 2 - points[3].y = tab_y - points[4].x = tab_x + tab_width - points[4].y = tab_y + 2 - points[5].x = tab_x + tab_width - points[5].y = tab_y + tab_height - 1 - points[6] = points[0] - - dc.SetClippingRect(in_rect) - dc.DrawPolygon(points) - - dc.SetPen(wx.GREY_PEN) - dc.DrawLines(points) - - close_button_width = 0 - - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - - close_button_width = self._active_close_bmp.GetWidth() - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - if control: - text_offset = tab_x + (tab_height/2) + close_button_width - (textx/2) - 2 - else: - text_offset = tab_x + (tab_height/2) + ((tab_width+close_button_width)/2) - (textx/2) - 2 - else: - if control: - text_offset = tab_x + (tab_height/2) + close_button_width - (textx/2) - else: - text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2) - - else: - - text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2) - if control: - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - text_offset = tab_x + (tab_height/3) - (textx/2) + close_button_width + 2 - else: - text_offset = tab_x + (tab_height/3) - (textx/2) - - # set minimum text offset - if text_offset < tab_x + tab_height: - text_offset = tab_x + tab_height - - # chop text if necessary - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x)) - else: - draw_text = ChopText(dc, caption, - tab_width - (text_offset-tab_x) - close_button_width) - - ypos = (tab_y + tab_height)/2 - (texty/2) + 1 - - if control is not None: - if control.GetPosition() != wx.Point(text_offset+1, ypos): - control.SetPosition(wx.Point(text_offset+1, ypos)) - - if not control.IsShown(): - control.Show() - - if paint_control: - bmp = TakeScreenShot(control.GetScreenRect()) - dc.DrawBitmap(bmp, text_offset+1, ypos, True) - - controlW, controlH = control.GetSize() - text_offset += controlW + 4 - - # draw tab text - rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text) - dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty)) - - # draw focus rectangle - if page.active and wx.Window.FindFocus() == wnd and (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0: - - focusRect = wx.Rect(text_offset, ((tab_y + tab_height)/2 - (texty/2) + 1), - selected_textx, selected_texty) - - focusRect.Inflate(2, 2) - # TODO: - # This should be uncommented when DrawFocusRect will become - # available in wxPython - # wx.RendererNative.Get().DrawFocusRect(wnd, dc, focusRect, 0) - - out_button_rect = wx.Rect() - # draw close button if necessary - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - - if page.active: - bmp = self._active_close_bmp - else: - bmp = self._disabled_close_bmp - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - rect = wx.Rect(tab_x + tab_height - 2, - tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1, - close_button_width, tab_height - 1) - else: - rect = wx.Rect(tab_x + tab_width - close_button_width - 1, - tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1, - close_button_width, tab_height - 1) - - self.DrawButtons(dc, rect, bmp, wx.WHITE, close_button_state) - out_button_rect = wx.Rect(*rect) - - out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height) - dc.DestroyClippingRegion() - - return out_tab_rect, out_button_rect, x_extent - - - def DrawButtons(self, dc, _rect, bmp, bkcolour, button_state): - """ - Convenience method to draw tab buttons. - - :param `dc`: a :class:`DC` device context; - :param Rect `_rect`: the tab rectangle; - :param Bitmap `bmp`: the tab bitmap; - :param Colour `bkcolour`: the tab background colour; - :param integer `button_state`: the state of the tab button. - """ - - rect = wx.Rect(*_rect) - - if button_state == AUI_BUTTON_STATE_PRESSED: - rect.x += 1 - rect.y += 1 - - if button_state in [AUI_BUTTON_STATE_HOVER, AUI_BUTTON_STATE_PRESSED]: - dc.SetBrush(wx.Brush(StepColour(bkcolour, 120))) - dc.SetPen(wx.Pen(StepColour(bkcolour, 75))) - - # draw the background behind the button - dc.DrawRectangle(rect.x, rect.y, 15, 15) - - # draw the button itself - dc.DrawBitmap(bmp, rect.x, rect.y, True) - - - def GetIndentSize(self): - """ Returns the tabs indent size. """ - - return 0 - - - def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None): - """ - Returns the tab size for the given caption, bitmap and button state. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param string `caption`: the tab text caption; - :param Bitmap `bitmap`: the bitmap displayed on the tab; - :param bool `active`: whether the tab is selected or not; - :param integer `close_button_state`: the state of the close button on the tab; - :param Window `control`: a :class:`Window` instance inside a tab (or ``None``). - """ - - dc.SetFont(self._measuring_font) - measured_textx, measured_texty, dummy = dc.GetMultiLineTextExtent(caption) - - tab_height = measured_texty + 4 - tab_width = measured_textx + tab_height + 5 - - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - tab_width += self._active_close_bmp.GetWidth() - - if self._agwFlags & AUI_NB_TAB_FIXED_WIDTH: - tab_width = self._fixed_tab_width - - if control is not None: - controlW, controlH = control.GetSize() - tab_width += controlW + 4 - - x_extent = tab_width - (tab_height/2) - 1 - - return (tab_width, tab_height), x_extent - - - def DrawButton(self, dc, wnd, in_rect, button, orientation): - """ - Draws a button on the tab or on the tab area, depending on the button identifier. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param Rect `in_rect`: rectangle the tab should be confined to; - :param `button`: an instance of the button class; - :param integer `orientation`: the tab orientation. - """ - - bitmap_id, button_state = button.id, button.cur_state - - if bitmap_id == AUI_BUTTON_CLOSE: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = self._disabled_close_bmp - else: - bmp = self._active_close_bmp - - elif bitmap_id == AUI_BUTTON_LEFT: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = self._disabled_left_bmp - else: - bmp = self._active_left_bmp - - elif bitmap_id == AUI_BUTTON_RIGHT: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = self._disabled_right_bmp - else: - bmp = self._active_right_bmp - - elif bitmap_id == AUI_BUTTON_WINDOWLIST: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = self._disabled_windowlist_bmp - else: - bmp = self._active_windowlist_bmp - - else: - if button_state & AUI_BUTTON_STATE_DISABLED: - bmp = button.dis_bitmap - else: - bmp = button.bitmap - - if not bmp.IsOk(): - return - - rect = wx.Rect(*in_rect) - - if orientation == wx.LEFT: - - rect.SetX(in_rect.x) - rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2)) - rect.SetWidth(bmp.GetWidth()) - rect.SetHeight(bmp.GetHeight()) - - else: - - rect = wx.Rect(in_rect.x + in_rect.width - bmp.GetWidth(), - ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2), - bmp.GetWidth(), bmp.GetHeight()) - - self.DrawButtons(dc, rect, bmp, wx.WHITE, button_state) - - out_rect = wx.Rect(*rect) - return out_rect - - - def ShowDropDown(self, wnd, pages, active_idx): - """ - Shows the drop-down window menu on the tab area. - - :param `wnd`: a :class:`Window` derived window instance; - :param list `pages`: the pages associated with the tabs; - :param integer `active_idx`: the active tab index. - """ - - menuPopup = wx.Menu() - useImages = self.GetAGWFlags() & AUI_NB_USE_IMAGES_DROPDOWN - - for i, page in enumerate(pages): - - if useImages: - menuItem = wx.MenuItem(menuPopup, 1000+i, page.caption) - if page.bitmap: - menuItem.SetBitmap(page.bitmap) - - menuPopup.AppendItem(menuItem) - - else: - - menuPopup.AppendCheckItem(1000+i, page.caption) - - menuPopup.Enable(1000+i, page.enabled) - - if active_idx != -1 and not useImages: - menuPopup.Check(1000+active_idx, True) - - # find out where to put the popup menu of window - # items. Subtract 100 for now to center the menu - # a bit, until a better mechanism can be implemented - pt = wx.GetMousePosition() - pt = wnd.ScreenToClient(pt) - - if pt.x < 100: - pt.x = 0 - else: - pt.x -= 100 - - # find out the screen coordinate at the bottom of the tab ctrl - cli_rect = wnd.GetClientRect() - pt.y = cli_rect.y + cli_rect.height - - cc = AuiCommandCapture() - wnd.PushEventHandler(cc) - wnd.PopupMenu(menuPopup, pt) - command = cc.GetCommandId() - wnd.PopEventHandler(True) - - if command >= 1000: - return command-1000 - - return -1 - - - def GetBestTabCtrlSize(self, wnd, pages, required_bmp_size): - """ - Returns the best tab control size. - - :param `wnd`: a :class:`Window` instance object; - :param list `pages`: the pages associated with the tabs; - :param Size `required_bmp_size`: the size of the bitmap on the tabs. - """ - - dc = wx.ClientDC(wnd) - dc.SetFont(self._measuring_font) - s, x_extent = self.GetTabSize(dc, wnd, "ABCDEFGHIj", wx.NullBitmap, True, - AUI_BUTTON_STATE_HIDDEN, None) - - max_y = s[1] - - for page in pages: - if page.control: - controlW, controlH = page.control.GetSize() - max_y = max(max_y, controlH+4) - - textx, texty, dummy = dc.GetMultiLineTextExtent(page.caption) - max_y = max(max_y, texty) - - return max_y + 3 - - - def SetNormalFont(self, font): - """ - Sets the normal font for drawing tab labels. - - :param Font `font`: the new font to use to draw tab labels in their normal, un-selected state. - """ - - self._normal_font = font - - - def SetSelectedFont(self, font): - """ - Sets the selected tab font for drawing tab labels. - - :param Font `font`: the new font to use to draw tab labels in their selected state. - """ - - self._selected_font = font - - - def SetMeasuringFont(self, font): - """ - Sets the font for calculating text measurements. - - :param Font `font`: the new font to use to measure tab labels text extents. - """ - - self._measuring_font = font - - - def GetNormalFont(self): - """ Returns the normal font for drawing tab labels. """ - - return self._normal_font - - - def GetSelectedFont(self): - """ Returns the selected tab font for drawing tab labels. """ - - return self._selected_font - - - def GetMeasuringFont(self): - """ Returns the font for calculating text measurements. """ - - return self._measuring_font - - - def SetCustomButton(self, bitmap_id, button_state, bmp): - """ - Sets a custom bitmap for the close, left, right and window list buttons. - - :param integer `bitmap_id`: the button identifier; - :param integer `button_state`: the button state; - :param Bitmap `bmp`: the custom bitmap to use for the button. - """ - - if bitmap_id == AUI_BUTTON_CLOSE: - if button_state == AUI_BUTTON_STATE_NORMAL: - self._active_close_bmp = bmp - self._hover_close_bmp = self._active_close_bmp - self._pressed_close_bmp = self._active_close_bmp - self._disabled_close_bmp = self._active_close_bmp - - elif button_state == AUI_BUTTON_STATE_HOVER: - self._hover_close_bmp = bmp - elif button_state == AUI_BUTTON_STATE_PRESSED: - self._pressed_close_bmp = bmp - else: - self._disabled_close_bmp = bmp - - elif bitmap_id == AUI_BUTTON_LEFT: - if button_state & AUI_BUTTON_STATE_DISABLED: - self._disabled_left_bmp = bmp - else: - self._active_left_bmp = bmp - - elif bitmap_id == AUI_BUTTON_RIGHT: - if button_state & AUI_BUTTON_STATE_DISABLED: - self._disabled_right_bmp = bmp - else: - self._active_right_bmp = bmp - - elif bitmap_id == AUI_BUTTON_WINDOWLIST: - if button_state & AUI_BUTTON_STATE_DISABLED: - self._disabled_windowlist_bmp = bmp - else: - self._active_windowlist_bmp = bmp - - -class VC71TabArt(AuiDefaultTabArt): - """ A class to draw tabs using the Visual Studio 2003 (VC71) style. """ - - def __init__(self): - """ Default class constructor. """ - - AuiDefaultTabArt.__init__(self) - - - def Clone(self): - """ Clones the art object. """ - - art = type(self)() - art.SetNormalFont(self.GetNormalFont()) - art.SetSelectedFont(self.GetSelectedFont()) - art.SetMeasuringFont(self.GetMeasuringFont()) - - art = CopyAttributes(art, self) - return art - - - def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False): - """ - Draws a single tab. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param `page`: the tab control page associated with the tab; - :param Rect `in_rect`: rectangle the tab should be confined to; - :param integer `close_button_state`: the state of the close button on the tab; - :param bool `paint_control`: whether to draw the control inside a tab (if any) on a :class:`MemoryDC`. - """ - - # Visual studio 7.1 style - # This code is based on the renderer included in FlatNotebook - - # figure out the size of the tab - - control = page.control - tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active, - close_button_state, control) - - tab_height = self._tab_ctrl_height - 3 - tab_width = tab_size[0] - tab_x = in_rect.x - tab_y = in_rect.y + in_rect.height - tab_height - clip_width = tab_width - - if tab_x + clip_width > in_rect.x + in_rect.width - 4: - clip_width = (in_rect.x + in_rect.width) - tab_x - 4 - - dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3) - agwFlags = self.GetAGWFlags() - - if agwFlags & AUI_NB_BOTTOM: - tab_y -= 1 - - dc.SetPen((page.active and [wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DHIGHLIGHT))] or \ - [wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DSHADOW))])[0]) - dc.SetBrush((page.active and [wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE))] or \ - [wx.TRANSPARENT_BRUSH])[0]) - - if page.active: - - tabH = tab_height - 2 - dc.DrawRectangle(tab_x, tab_y, tab_width, tabH) - - rightLineY1 = (agwFlags & AUI_NB_BOTTOM and [vertical_border_padding - 2] or \ - [vertical_border_padding - 1])[0] - rightLineY2 = tabH + 3 - dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DSHADOW))) - dc.DrawLine(tab_x + tab_width - 1, rightLineY1 + 1, tab_x + tab_width - 1, rightLineY2) - - if agwFlags & AUI_NB_BOTTOM: - dc.DrawLine(tab_x + 1, rightLineY2 - 3 , tab_x + tab_width - 1, rightLineY2 - 3) - - dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW))) - dc.DrawLine(tab_x + tab_width, rightLineY1, tab_x + tab_width, rightLineY2) - - if agwFlags & AUI_NB_BOTTOM: - dc.DrawLine(tab_x, rightLineY2 - 2, tab_x + tab_width, rightLineY2 - 2) - - else: - - # We dont draw a rectangle for non selected tabs, but only - # vertical line on the right - blackLineY1 = (agwFlags & AUI_NB_BOTTOM and [vertical_border_padding + 2] or \ - [vertical_border_padding + 1])[0] - blackLineY2 = tab_height - 5 - dc.DrawLine(tab_x + tab_width, blackLineY1, tab_x + tab_width, blackLineY2) - - border_points = [0, 0] - - if agwFlags & AUI_NB_BOTTOM: - - border_points[0] = wx.Point(tab_x, tab_y) - border_points[1] = wx.Point(tab_x, tab_y + tab_height - 6) - - else: # if (agwFlags & AUI_NB_TOP) - - border_points[0] = wx.Point(tab_x, tab_y + tab_height - 4) - border_points[1] = wx.Point(tab_x, tab_y + 2) - - drawn_tab_yoff = border_points[1].y - drawn_tab_height = border_points[0].y - border_points[1].y - - text_offset = tab_x + 8 - close_button_width = 0 - - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - close_button_width = self._active_close_bmp.GetWidth() - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - text_offset += close_button_width - 5 - - if not page.enabled: - dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) - pagebitmap = page.dis_bitmap - else: - dc.SetTextForeground(page.text_colour) - pagebitmap = page.bitmap - - shift = 0 - if agwFlags & AUI_NB_BOTTOM: - shift = (page.active and [1] or [2])[0] - - bitmap_offset = 0 - if pagebitmap.IsOk(): - bitmap_offset = tab_x + 8 - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width: - bitmap_offset += close_button_width - 5 - - # draw bitmap - dc.DrawBitmap(pagebitmap, bitmap_offset, - drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2) + shift, - True) - - text_offset = bitmap_offset + pagebitmap.GetWidth() - text_offset += 3 # bitmap padding - - else: - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width: - text_offset = tab_x + 8 - - # if the caption is empty, measure some temporary text - caption = page.caption - - if caption == "": - caption = "Xj" - - if page.active: - dc.SetFont(self._selected_font) - textx, texty, dummy = dc.GetMultiLineTextExtent(caption) - else: - dc.SetFont(self._normal_font) - textx, texty, dummy = dc.GetMultiLineTextExtent(caption) - - draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width) - - ypos = drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1 + shift - - offset_focus = text_offset - - if control is not None: - if control.GetPosition() != wx.Point(text_offset+1, ypos): - control.SetPosition(wx.Point(text_offset+1, ypos)) - - if not control.IsShown(): - control.Show() - - if paint_control: - bmp = TakeScreenShot(control.GetScreenRect()) - dc.DrawBitmap(bmp, text_offset+1, ypos, True) - - controlW, controlH = control.GetSize() - text_offset += controlW + 4 - textx += controlW + 4 - - # draw tab text - rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text) - dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty)) - - out_button_rect = wx.Rect() - - # draw focus rectangle - if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0: - self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff+shift, - drawn_tab_height+shift, rectx, recty) - - # draw 'x' on tab (if enabled) - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - close_button_width = self._active_close_bmp.GetWidth() - - bmp = self._disabled_close_bmp - - if close_button_state == AUI_BUTTON_STATE_HOVER: - bmp = self._hover_close_bmp - elif close_button_state == AUI_BUTTON_STATE_PRESSED: - bmp = self._pressed_close_bmp - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - rect = wx.Rect(tab_x + 4, - drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift, - close_button_width, tab_height) - else: - rect = wx.Rect(tab_x + tab_width - close_button_width - 3, - drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift, - close_button_width, tab_height) - - # Indent the button if it is pressed down: - rect = IndentPressedBitmap(rect, close_button_state) - dc.DrawBitmap(bmp, rect.x, rect.y, True) - - out_button_rect = rect - - out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height) - dc.DestroyClippingRegion() - - return out_tab_rect, out_button_rect, x_extent - - -class FF2TabArt(AuiDefaultTabArt): - """ A class to draw tabs using the Firefox 2 (FF2) style. """ - - def __init__(self): - """ Default class constructor. """ - - AuiDefaultTabArt.__init__(self) - - - def Clone(self): - """ Clones the art object. """ - - art = type(self)() - art.SetNormalFont(self.GetNormalFont()) - art.SetSelectedFont(self.GetSelectedFont()) - art.SetMeasuringFont(self.GetMeasuringFont()) - - art = CopyAttributes(art, self) - return art - - - def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control): - """ - Returns the tab size for the given caption, bitmap and button state. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param string `caption`: the tab text caption; - :param Bitmap `bitmap`: the bitmap displayed on the tab; - :param bool `active`: whether the tab is selected or not; - :param integer `close_button_state`: the state of the close button on the tab; - :param Window `control`: a :class:`Window` instance inside a tab (or ``None``). - """ - - tab_size, x_extent = AuiDefaultTabArt.GetTabSize(self, dc, wnd, caption, bitmap, - active, close_button_state, control) - - tab_width, tab_height = tab_size - - # add some vertical padding - tab_height += 2 - - return (tab_width, tab_height), x_extent - - - def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False): - """ - Draws a single tab. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param `page`: the tab control page associated with the tab; - :param Rect `in_rect`: rectangle the tab should be confined to; - :param integer `close_button_state`: the state of the close button on the tab; - :param bool `paint_control`: whether to draw the control inside a tab (if any) on a :class:`MemoryDC`. - """ - - # Firefox 2 style - - control = page.control - - # figure out the size of the tab - tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, - page.active, close_button_state, control) - - tab_height = self._tab_ctrl_height - 2 - tab_width = tab_size[0] - tab_x = in_rect.x - tab_y = in_rect.y + in_rect.height - tab_height - - clip_width = tab_width - if tab_x + clip_width > in_rect.x + in_rect.width - 4: - clip_width = (in_rect.x + in_rect.width) - tab_x - 4 - - dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3) - - tabPoints = [wx.Point() for i in xrange(7)] - - adjust = 0 - if not page.active: - adjust = 1 - - agwFlags = self.GetAGWFlags() - - tabPoints[0].x = tab_x + 3 - tabPoints[0].y = (agwFlags & AUI_NB_BOTTOM and [3] or [tab_height - 2])[0] - - tabPoints[1].x = tabPoints[0].x - tabPoints[1].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - (vertical_border_padding + 2) - adjust] or \ - [(vertical_border_padding + 2) + adjust])[0] - - tabPoints[2].x = tabPoints[1].x+2 - tabPoints[2].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - vertical_border_padding - adjust] or \ - [vertical_border_padding + adjust])[0] - - tabPoints[3].x = tab_x + tab_width - 2 - tabPoints[3].y = tabPoints[2].y - - tabPoints[4].x = tabPoints[3].x + 2 - tabPoints[4].y = tabPoints[1].y - - tabPoints[5].x = tabPoints[4].x - tabPoints[5].y = tabPoints[0].y - - tabPoints[6].x = tabPoints[0].x - tabPoints[6].y = tabPoints[0].y - - rr = wx.RectPP(tabPoints[2], tabPoints[5]) - self.DrawTabBackground(dc, rr, page.active, (agwFlags & AUI_NB_BOTTOM) == 0) - - dc.SetBrush(wx.TRANSPARENT_BRUSH) - dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))) - - # Draw the tab as rounded rectangle - dc.DrawPolygon(tabPoints) - - if page.active: - dc.DrawLine(tabPoints[0].x + 1, tabPoints[0].y, tabPoints[5].x , tabPoints[0].y) - - drawn_tab_yoff = tabPoints[1].y - drawn_tab_height = tabPoints[0].y - tabPoints[2].y - - text_offset = tab_x + 8 - close_button_width = 0 - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - close_button_width = self._active_close_bmp.GetWidth() - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - text_offset += close_button_width - 4 - - if not page.enabled: - dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) - pagebitmap = page.dis_bitmap - else: - dc.SetTextForeground(page.text_colour) - pagebitmap = page.bitmap - - shift = -1 - if agwFlags & AUI_NB_BOTTOM: - shift = 2 - - bitmap_offset = 0 - if pagebitmap.IsOk(): - bitmap_offset = tab_x + 8 - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width: - bitmap_offset += close_button_width - 4 - - # draw bitmap - dc.DrawBitmap(pagebitmap, bitmap_offset, - drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2) + shift, - True) - - text_offset = bitmap_offset + pagebitmap.GetWidth() - text_offset += 3 # bitmap padding - - else: - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width: - text_offset = tab_x + 8 - - # if the caption is empty, measure some temporary text - caption = page.caption - if caption == "": - caption = "Xj" - - if page.active: - dc.SetFont(self._selected_font) - textx, texty, dummy = dc.GetMultiLineTextExtent(caption) - else: - dc.SetFont(self._normal_font) - textx, texty, dummy = dc.GetMultiLineTextExtent(caption) - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width + 1) - else: - draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width) - - ypos = drawn_tab_yoff + drawn_tab_height/2 - texty/2 - 1 + shift - - offset_focus = text_offset - - if control is not None: - if control.GetPosition() != wx.Point(text_offset+1, ypos): - control.SetPosition(wx.Point(text_offset+1, ypos)) - - if not control.IsShown(): - control.Show() - - if paint_control: - bmp = TakeScreenShot(control.GetScreenRect()) - dc.DrawBitmap(bmp, text_offset+1, ypos, True) - - controlW, controlH = control.GetSize() - text_offset += controlW + 4 - textx += controlW + 4 - - # draw tab text - rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text) - dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty)) - - # draw focus rectangle - if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0: - self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff+shift, - drawn_tab_height, rectx, recty) - - out_button_rect = wx.Rect() - # draw 'x' on tab (if enabled) - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - - close_button_width = self._active_close_bmp.GetWidth() - bmp = self._disabled_close_bmp - - if close_button_state == AUI_BUTTON_STATE_HOVER: - bmp = self._hover_close_bmp - elif close_button_state == AUI_BUTTON_STATE_PRESSED: - bmp = self._pressed_close_bmp - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - rect = wx.Rect(tab_x + 5, - drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift, - close_button_width, tab_height) - else: - rect = wx.Rect(tab_x + tab_width - close_button_width - 3, - drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift, - close_button_width, tab_height) - - # Indent the button if it is pressed down: - rect = IndentPressedBitmap(rect, close_button_state) - dc.DrawBitmap(bmp, rect.x, rect.y, True) - out_button_rect = rect - - out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height) - dc.DestroyClippingRegion() - - return out_tab_rect, out_button_rect, x_extent - - - def DrawTabBackground(self, dc, rect, focus, upperTabs): - """ - Draws the tab background for the Firefox 2 style. - This is more consistent with :class:`~lib.agw.flatnotebook.FlatNotebook` than before. - - :param `dc`: a :class:`DC` device context; - :param Rect `rect`: rectangle the tab should be confined to; - :param bool `focus`: whether the tab has focus or not; - :param bool `upperTabs`: whether the style is ``AUI_NB_TOP`` or ``AUI_NB_BOTTOM``. - """ - - # Define the rounded rectangle base on the given rect - # we need an array of 9 points for it - regPts = [wx.Point() for indx in xrange(9)] - - if focus: - if upperTabs: - leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*8) - rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*8) - else: - leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*5) - rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*5) - else: - leftPt = wx.Point(rect.x, rect.y + (rect.height / 2)) - rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 2)) - - # Define the top region - top = wx.RectPP(rect.GetTopLeft(), rightPt) - bottom = wx.RectPP(leftPt, rect.GetBottomRight()) - - topStartColour = wx.WHITE - - if not focus: - topStartColour = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 50) - - topEndColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) - bottomStartColour = topEndColour - bottomEndColour = topEndColour - - # Incase we use bottom tabs, switch the colours - if upperTabs: - if focus: - dc.GradientFillLinear(top, topStartColour, topEndColour, wx.SOUTH) - dc.GradientFillLinear(bottom, bottomStartColour, bottomEndColour, wx.SOUTH) - else: - dc.GradientFillLinear(top, topEndColour , topStartColour, wx.SOUTH) - dc.GradientFillLinear(bottom, bottomStartColour, bottomEndColour, wx.SOUTH) - - else: - if focus: - dc.GradientFillLinear(bottom, topEndColour, bottomEndColour, wx.SOUTH) - dc.GradientFillLinear(top, topStartColour, topStartColour, wx.SOUTH) - else: - dc.GradientFillLinear(bottom, bottomStartColour, bottomEndColour, wx.SOUTH) - dc.GradientFillLinear(top, topEndColour, topStartColour, wx.SOUTH) - - dc.SetBrush(wx.TRANSPARENT_BRUSH) - - -class VC8TabArt(AuiDefaultTabArt): - """ A class to draw tabs using the Visual Studio 2005 (VC8) style. """ - - def __init__(self): - """ Default class constructor. """ - - AuiDefaultTabArt.__init__(self) - - - def Clone(self): - """ Clones the art object. """ - - art = type(self)() - art.SetNormalFont(self.GetNormalFont()) - art.SetSelectedFont(self.GetSelectedFont()) - art.SetMeasuringFont(self.GetMeasuringFont()) - - art = CopyAttributes(art, self) - return art - - - def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth): - """ - Sets the tab sizing information. - - :param Size `tab_ctrl_size`: the size of the tab control area; - :param integer `tab_count`: the number of tabs; - :param tuple `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths - to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active. - """ - - AuiDefaultTabArt.SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth) - - minTabWidth, maxTabWidth = minMaxTabWidth - if minTabWidth > -1: - self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth) - if maxTabWidth > -1: - self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth) - - self._fixed_tab_width -= 5 - - - def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None): - """ - Returns the tab size for the given caption, bitmap and button state. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param string `caption`: the tab text caption; - :param Bitmap `bitmap`: the bitmap displayed on the tab; - :param bool `active`: whether the tab is selected or not; - :param integer `close_button_state`: the state of the close button on the tab; - :param Window `control`: a :class:`Window` instance inside a tab (or ``None``). - """ - - tab_size, x_extent = AuiDefaultTabArt.GetTabSize(self, dc, wnd, caption, bitmap, - active, close_button_state, control) - - tab_width, tab_height = tab_size - - # add some padding - tab_width += 10 - - if not bitmap.IsOk(): - tab_width += 5 - - tab_height += 2 - - return (tab_width, tab_height), x_extent - - - def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False): - """ - Draws a single tab. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param `page`: the tab control page associated with the tab; - :param Rect `in_rect`: rectangle the tab should be confined to; - :param integer `close_button_state`: the state of the close button on the tab; - :param bool `paint_control`: whether to draw the control inside a tab (if any) on a :class:`MemoryDC`. - """ - - # Visual Studio 8 style - - control = page.control - - # figure out the size of the tab - tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, - page.active, close_button_state, control) - - tab_height = self._tab_ctrl_height - 1 - tab_width = tab_size[0] - tab_x = in_rect.x - tab_y = in_rect.y + in_rect.height - tab_height - - clip_width = tab_width + 3 - if tab_x + clip_width > in_rect.x + in_rect.width - 4: - clip_width = (in_rect.x + in_rect.width) - tab_x - 4 - - tabPoints = [wx.Point() for i in xrange(8)] - - # If we draw the first tab or the active tab, - # we draw a full tab, else we draw a truncated tab - # - # X(2) X(3) - # X(1) X(4) - # - # X(5) - # - # X(0),(7) X(6) - # - # - - adjust = 0 - if not page.active: - adjust = 1 - - agwFlags = self.GetAGWFlags() - tabPoints[0].x = (agwFlags & AUI_NB_BOTTOM and [tab_x] or [tab_x + adjust])[0] - tabPoints[0].y = (agwFlags & AUI_NB_BOTTOM and [2] or [tab_height - 3])[0] - - tabPoints[1].x = tabPoints[0].x + tab_height - vertical_border_padding - 3 - adjust - tabPoints[1].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - (vertical_border_padding+2)] or \ - [(vertical_border_padding+2)])[0] - - tabPoints[2].x = tabPoints[1].x + 4 - tabPoints[2].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - vertical_border_padding] or \ - [vertical_border_padding])[0] - - tabPoints[3].x = tabPoints[2].x + tab_width - tab_height + vertical_border_padding - tabPoints[3].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - vertical_border_padding] or \ - [vertical_border_padding])[0] - - tabPoints[4].x = tabPoints[3].x + 1 - tabPoints[4].y = (agwFlags & AUI_NB_BOTTOM and [tabPoints[3].y - 1] or [tabPoints[3].y + 1])[0] - - tabPoints[5].x = tabPoints[4].x + 1 - tabPoints[5].y = (agwFlags & AUI_NB_BOTTOM and [(tabPoints[4].y - 1)] or [tabPoints[4].y + 1])[0] - - tabPoints[6].x = tabPoints[2].x + tab_width - tab_height + 2 + vertical_border_padding - tabPoints[6].y = tabPoints[0].y - - tabPoints[7].x = tabPoints[0].x - tabPoints[7].y = tabPoints[0].y - - self.FillVC8GradientColour(dc, tabPoints, page.active) - - dc.SetBrush(wx.TRANSPARENT_BRUSH) - - dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW))) - dc.DrawPolygon(tabPoints) - - if page.active: - # Delete the bottom line (or the upper one, incase we use wxBOTTOM) - dc.SetPen(wx.WHITE_PEN) - dc.DrawLine(tabPoints[0].x, tabPoints[0].y, tabPoints[6].x, tabPoints[6].y) - - dc.SetClippingRegion(tab_x, tab_y, clip_width + 2, tab_height - 3) - - drawn_tab_yoff = tabPoints[1].y - drawn_tab_height = tabPoints[0].y - tabPoints[2].y - - text_offset = tab_x + 20 - close_button_width = 0 - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - close_button_width = self._active_close_bmp.GetWidth() - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - text_offset += close_button_width - - if not page.enabled: - dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) - pagebitmap = page.dis_bitmap - else: - dc.SetTextForeground(page.text_colour) - pagebitmap = page.bitmap - - shift = 0 - if agwFlags & AUI_NB_BOTTOM: - shift = (page.active and [1] or [2])[0] - - bitmap_offset = 0 - if pagebitmap.IsOk(): - bitmap_offset = tab_x + 20 - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width: - bitmap_offset += close_button_width - - # draw bitmap - dc.DrawBitmap(pagebitmap, bitmap_offset, - drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2) + shift, - True) - - text_offset = bitmap_offset + pagebitmap.GetWidth() - text_offset += 3 # bitmap padding - - else: - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width: - text_offset = tab_x + tab_height - - # if the caption is empty, measure some temporary text - caption = page.caption - if caption == "": - caption = "Xj" - - if page.active: - dc.SetFont(self._selected_font) - textx, texty, dummy = dc.GetMultiLineTextExtent(caption) - else: - dc.SetFont(self._normal_font) - textx, texty, dummy = dc.GetMultiLineTextExtent(caption) - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x)) - else: - draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width) - - ypos = drawn_tab_yoff + drawn_tab_height/2 - texty/2 - 1 + shift - - offset_focus = text_offset - - if control is not None: - if control.GetPosition() != wx.Point(text_offset+1, ypos): - control.SetPosition(wx.Point(text_offset+1, ypos)) - - if not control.IsShown(): - control.Show() - - if paint_control: - bmp = TakeScreenShot(control.GetScreenRect()) - dc.DrawBitmap(bmp, text_offset+1, ypos, True) - - controlW, controlH = control.GetSize() - text_offset += controlW + 4 - textx += controlW + 4 - - # draw tab text - rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text) - dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty)) - - # draw focus rectangle - if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0: - self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff+shift, - drawn_tab_height+shift, rectx, recty) - - out_button_rect = wx.Rect() - # draw 'x' on tab (if enabled) - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - - close_button_width = self._active_close_bmp.GetWidth() - bmp = self._disabled_close_bmp - - if close_button_state == AUI_BUTTON_STATE_HOVER: - bmp = self._hover_close_bmp - elif close_button_state == AUI_BUTTON_STATE_PRESSED: - bmp = self._pressed_close_bmp - - if page.active: - xpos = tab_x + tab_width - close_button_width + 3 - else: - xpos = tab_x + tab_width - close_button_width - 5 - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - rect = wx.Rect(tab_x + 20, - drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift, - close_button_width, tab_height) - else: - rect = wx.Rect(xpos, - drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift, - close_button_width, tab_height) - - # Indent the button if it is pressed down: - rect = IndentPressedBitmap(rect, close_button_state) - dc.DrawBitmap(bmp, rect.x, rect.y, True) - out_button_rect = rect - - out_tab_rect = wx.Rect(tab_x, tab_y, x_extent, tab_height) - dc.DestroyClippingRegion() - - return out_tab_rect, out_button_rect, x_extent - - - def FillVC8GradientColour(self, dc, tabPoints, active): - """ - Fills the tab with the Visual Studio 2005 gradient background. - - :param `dc`: a :class:`DC` device context; - :param list `tabPoints`: a list of :class:`Point` objects describing the tab shape; - :param bool `active`: whether the tab is selected or not. - """ - - xList = [pt.x for pt in tabPoints] - yList = [pt.y for pt in tabPoints] - - minx, maxx = min(xList), max(xList) - miny, maxy = min(yList), max(yList) - - rect = wx.Rect(minx, maxy, maxx-minx, miny-maxy+1) - region = wx.RegionFromPoints(tabPoints) - - if self._buttonRect.width > 0: - buttonRegion = wx.Region(*self._buttonRect) - region.XorRegion(buttonRegion) - - dc.SetClippingRegionAsRegion(region) - - if active: - bottom_colour = top_colour = wx.WHITE - else: - bottom_colour = StepColour(self._base_colour, 90) - top_colour = StepColour(self._base_colour, 170) - - dc.GradientFillLinear(rect, top_colour, bottom_colour, wx.SOUTH) - dc.DestroyClippingRegion() - - -class ChromeTabArt(AuiDefaultTabArt): - """ - A class to draw tabs using the Google Chrome browser style. - It uses custom bitmap to render the tabs, so that the look and feel is as close - as possible to the Chrome style. - """ - - def __init__(self): - """ Default class constructor. """ - - AuiDefaultTabArt.__init__(self) - - self.SetBitmaps(mirror=False) - - closeBmp = tab_close.GetBitmap() - closeHBmp = tab_close_h.GetBitmap() - closePBmp = tab_close_p.GetBitmap() - - self.SetCustomButton(AUI_BUTTON_CLOSE, AUI_BUTTON_STATE_NORMAL, closeBmp) - self.SetCustomButton(AUI_BUTTON_CLOSE, AUI_BUTTON_STATE_HOVER, closeHBmp) - self.SetCustomButton(AUI_BUTTON_CLOSE, AUI_BUTTON_STATE_PRESSED, closePBmp) - - - def SetAGWFlags(self, agwFlags): - """ - Sets the tab art flags. - - :param integer `agwFlags`: a combination of the following values: - - ==================================== ================================== - Flag name Description - ==================================== ================================== - ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook - ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet. - ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet. - ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook - ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab - ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging - ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control - ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width - ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed - ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available - ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar - ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab - ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs - ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close :class:`~lib.agw.aui.auibook.AuiNotebook` tabs by mouse middle button click - ``AUI_NB_SUB_NOTEBOOK`` This style is used by :class:`~lib.agw.aui.framemanager.AuiManager` to create automatic AuiNotebooks - ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present - ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows - ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items - ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser) - ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less full - screen, tabs cannot be dragged far enough outside of the notebook to become floating pages - ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default) - ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs - ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle - ==================================== ================================== - - :note: Overridden from :class:`AuiDefaultTabArt`. - """ - - if agwFlags & AUI_NB_TOP: - self.SetBitmaps(mirror=False) - elif agwFlags & AUI_NB_BOTTOM: - self.SetBitmaps(mirror=True) - - AuiDefaultTabArt.SetAGWFlags(self, agwFlags) - - - def SetBitmaps(self, mirror): - """ - Assigns the tab custom bitmaps - - :param bool `mirror`: whether to vertically mirror the bitmap or not. - """ - - bmps = [tab_active_left.GetBitmap(), tab_active_center.GetBitmap(), - tab_active_right.GetBitmap(), tab_inactive_left.GetBitmap(), - tab_inactive_center.GetBitmap(), tab_inactive_right.GetBitmap()] - - if mirror: - for indx, bmp in enumerate(bmps): - img = bmp.ConvertToImage() - img = img.Mirror(horizontally=False) - bmps[indx] = img.ConvertToBitmap() - - self._leftActiveBmp = bmps[0] - self._centerActiveBmp = bmps[1] - self._rightActiveBmp = bmps[2] - self._leftInactiveBmp = bmps[3] - self._centerInactiveBmp = bmps[4] - self._rightInactiveBmp = bmps[5] - - - def Clone(self): - """ Clones the art object. """ - - art = type(self)() - art.SetNormalFont(self.GetNormalFont()) - art.SetSelectedFont(self.GetSelectedFont()) - art.SetMeasuringFont(self.GetMeasuringFont()) - - art = CopyAttributes(art, self) - return art - - - def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth): - """ - Sets the tab sizing information. - - :param Size `tab_ctrl_size`: the size of the tab control area; - :param integer `tab_count`: the number of tabs; - :param tuple `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths - to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active. - """ - - AuiDefaultTabArt.SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth) - - minTabWidth, maxTabWidth = minMaxTabWidth - if minTabWidth > -1: - self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth) - if maxTabWidth > -1: - self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth) - - self._fixed_tab_width -= 5 - - - def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None): - """ - Returns the tab size for the given caption, bitmap and button state. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param string `caption`: the tab text caption; - :param Bitmap `bitmap`: the bitmap displayed on the tab; - :param bool `active`: whether the tab is selected or not; - :param integer `close_button_state`: the state of the close button on the tab; - :param Window `control`: a :class:`Window` instance inside a tab (or ``None``). - """ - - tab_size, x_extent = AuiDefaultTabArt.GetTabSize(self, dc, wnd, caption, bitmap, - active, close_button_state, control) - - tab_width, tab_height = tab_size - - # add some padding - tab_width += self._leftActiveBmp.GetWidth() - tab_height += 2 - - tab_height = max(tab_height, self._centerActiveBmp.GetHeight()) - - return (tab_width, tab_height), x_extent - - - def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False): - """ - Draws a single tab. - - :param `dc`: a :class:`DC` device context; - :param `wnd`: a :class:`Window` instance object; - :param `page`: the tab control page associated with the tab; - :param Rect `in_rect`: rectangle the tab should be confined to; - :param integer `close_button_state`: the state of the close button on the tab; - :param bool `paint_control`: whether to draw the control inside a tab (if any) on a :class:`MemoryDC`. - """ - - # Chrome tab style - - control = page.control - # figure out the size of the tab - tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active, - close_button_state, control) - - agwFlags = self.GetAGWFlags() - - tab_height = self._tab_ctrl_height - 1 - tab_width = tab_size[0] - tab_x = in_rect.x - tab_y = in_rect.y + in_rect.height - tab_height - clip_width = tab_width - - if tab_x + clip_width > in_rect.x + in_rect.width - 4: - clip_width = (in_rect.x + in_rect.width) - tab_x - 4 - - dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3) - drawn_tab_yoff = 1 - - if page.active: - left = self._leftActiveBmp - center = self._centerActiveBmp - right = self._rightActiveBmp - else: - left = self._leftInactiveBmp - center = self._centerInactiveBmp - right = self._rightInactiveBmp - - dc.DrawBitmap(left, tab_x, tab_y) - leftw = left.GetWidth() - centerw = center.GetWidth() - rightw = right.GetWidth() - - available = tab_x + tab_width - rightw - posx = tab_x + leftw - - while 1: - if posx >= available: - break - dc.DrawBitmap(center, posx, tab_y) - posx += centerw - - dc.DrawBitmap(right, posx, tab_y) - - drawn_tab_height = center.GetHeight() - text_offset = tab_x + leftw - - close_button_width = 0 - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - close_button_width = self._active_close_bmp.GetWidth() - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - text_offset += close_button_width - - if not page.enabled: - dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) - pagebitmap = page.dis_bitmap - else: - dc.SetTextForeground(page.text_colour) - pagebitmap = page.bitmap - - bitmap_offset = 0 - if pagebitmap.IsOk(): - bitmap_offset = tab_x + leftw - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width: - bitmap_offset += close_button_width - - # draw bitmap - dc.DrawBitmap(pagebitmap, bitmap_offset, - drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2), - True) - - text_offset = bitmap_offset + pagebitmap.GetWidth() - text_offset += 3 # bitmap padding - - else: - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width: - text_offset = tab_x + leftw - - # if the caption is empty, measure some temporary text - caption = page.caption - if caption == "": - caption = "Xj" - - if page.active: - dc.SetFont(self._selected_font) - textx, texty, dummy = dc.GetMultiLineTextExtent(caption) - else: - dc.SetFont(self._normal_font) - textx, texty, dummy = dc.GetMultiLineTextExtent(caption) - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - leftw) - else: - draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width - leftw) - - ypos = drawn_tab_yoff + drawn_tab_height/2 - texty/2 - 1 - - if control is not None: - if control.GetPosition() != wx.Point(text_offset+1, ypos): - control.SetPosition(wx.Point(text_offset+1, ypos)) - - if not control.IsShown(): - control.Show() - - if paint_control: - bmp = TakeScreenShot(control.GetScreenRect()) - dc.DrawBitmap(bmp, text_offset+1, ypos, True) - - controlW, controlH = control.GetSize() - text_offset += controlW + 4 - - # draw tab text - rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text) - dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty)) - - out_button_rect = wx.Rect() - # draw 'x' on tab (if enabled) - if close_button_state != AUI_BUTTON_STATE_HIDDEN: - - close_button_width = self._active_close_bmp.GetWidth() - bmp = self._disabled_close_bmp - - if close_button_state == AUI_BUTTON_STATE_HOVER: - bmp = self._hover_close_bmp - elif close_button_state == AUI_BUTTON_STATE_PRESSED: - bmp = self._pressed_close_bmp - - if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT: - rect = wx.Rect(tab_x + leftw - 2, - drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + 1, - close_button_width, tab_height) - else: - rect = wx.Rect(tab_x + tab_width - close_button_width - rightw + 2, - drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + 1, - close_button_width, tab_height) - - if agwFlags & AUI_NB_BOTTOM: - rect.y -= 1 - - # Indent the button if it is pressed down: - rect = IndentPressedBitmap(rect, close_button_state) - dc.DrawBitmap(bmp, rect.x, rect.y, True) - out_button_rect = rect - - out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height) - dc.DestroyClippingRegion() - - return out_tab_rect, out_button_rect, x_extent - - diff --git a/enaml/wx/wx_upstream/aui/tabmdi.py b/enaml/wx/wx_upstream/aui/tabmdi.py deleted file mode 100644 index ef09e9fc8..000000000 --- a/enaml/wx/wx_upstream/aui/tabmdi.py +++ /dev/null @@ -1,666 +0,0 @@ -__author__ = "Andrea Gavana " -__date__ = "31 March 2009" - - -import wx - -import auibook -from aui_constants import * - -_ = wx.GetTranslation - -#----------------------------------------------------------------------------- -# AuiMDIParentFrame -#----------------------------------------------------------------------------- - -class AuiMDIParentFrame(wx.Frame): - - def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, - size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE|wx.VSCROLL|wx.HSCROLL, - name="AuiMDIParentFrame"): - - wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name) - self.Init() - - self.Bind(wx.EVT_MENU, self.DoHandleMenu, id=wx.ID_ANY) - - # this style can be used to prevent a window from having the standard MDI - # "Window" menu - if not style & wx.FRAME_NO_WINDOW_MENU: - - self._pWindowMenu = wx.Menu() - self._pWindowMenu.Append(wxWINDOWCLOSE, _("Cl&ose")) - self._pWindowMenu.Append(wxWINDOWCLOSEALL, _("Close All")) - self._pWindowMenu.AppendSeparator() - self._pWindowMenu.Append(wxWINDOWNEXT, _("&Next")) - self._pWindowMenu.Append(wxWINDOWPREV, _("&Previous")) - - self._pClientWindow = self.OnCreateClient() - - - def SetArtProvider(self, provider): - - if self._pClientWindow: - self._pClientWindow.SetArtProvider(provider) - - - def GetArtProvider(self): - - if not self._pClientWindow: - return None - - return self._pClientWindow.GetArtProvider() - - - def GetNotebook(self): - - return self._pClientWindow - - - def SetWindowMenu(self, pMenu): - - # Replace the window menu from the currently loaded menu bar. - pMenuBar = self.GetMenuBar() - - if self._pWindowMenu: - self.RemoveWindowMenu(pMenuBar) - del self._pWindowMenu - self._pWindowMenu = None - - if pMenu: - self._pWindowMenu = pMenu - self.AddWindowMenu(pMenuBar) - - - def GetWindowMenu(self): - - return self._pWindowMenu - - - def SetMenuBar(self, pMenuBar): - - # Remove the Window menu from the old menu bar - self.RemoveWindowMenu(self.GetMenuBar()) - - # Add the Window menu to the new menu bar. - self.AddWindowMenu(pMenuBar) - - wx.Frame.SetMenuBar(self, pMenuBar) - - - def SetChildMenuBar(self, pChild): - - if not pChild: - - # No Child, set Our menu bar back. - if self._pMyMenuBar: - self.SetMenuBar(self._pMyMenuBar) - else: - self.SetMenuBar(self.GetMenuBar()) - - # Make sure we know our menu bar is in use - self._pMyMenuBar = None - - else: - - if pChild.GetMenuBar() == None: - return - - # Do we need to save the current bar? - if self._pMyMenuBar == None: - self._pMyMenuBar = self.GetMenuBar() - - self.SetMenuBar(pChild.GetMenuBar()) - - - def ProcessEvent(self, event): - - # stops the same event being processed repeatedly - if self._pLastEvt == event: - return False - - self._pLastEvt = event - - # let the active child (if any) process the event first. - res = False - if self._pActiveChild and event.IsCommandEvent() and \ - event.GetEventObject() != self._pClientWindow and \ - event.GetEventType() not in [wx.wxEVT_ACTIVATE, wx.wxEVT_SET_FOCUS, - wx.wxEVT_KILL_FOCUS, wx.wxEVT_CHILD_FOCUS, - wx.wxEVT_COMMAND_SET_FOCUS, wx.wxEVT_COMMAND_KILL_FOCUS]: - - res = self._pActiveChild.GetEventHandler().ProcessEvent(event) - - if not res: - - # if the event was not handled this frame will handle it, - # which is why we need the protection code at the beginning - # of this method - res = self.GetEventHandler().ProcessEvent(event) - - self._pLastEvt = None - - return res - - - def GetActiveChild(self): - - return self._pActiveChild - - - def SetActiveChild(self, pChildFrame): - - self._pActiveChild = pChildFrame - - - def GetClientWindow(self): - - return self._pClientWindow - - - def OnCreateClient(self): - - return AuiMDIClientWindow(self) - - - def ActivateNext(self): - - if self._pClientWindow and self._pClientWindow.GetSelection() != wx.NOT_FOUND: - - active = self._pClientWindow.GetSelection() + 1 - if active >= self._pClientWindow.GetPageCount(): - active = 0 - - self._pClientWindow.SetSelection(active) - - - def ActivatePrevious(self): - - if self._pClientWindow and self._pClientWindow.GetSelection() != wx.NOT_FOUND: - - active = self._pClientWindow.GetSelection() - 1 - if active < 0: - active = self._pClientWindow.GetPageCount() - 1 - - self._pClientWindow.SetSelection(active) - - - def Init(self): - - self._pLastEvt = None - - self._pClientWindow = None - self._pActiveChild = None - self._pWindowMenu = None - self._pMyMenuBar = None - - - def RemoveWindowMenu(self, pMenuBar): - - if pMenuBar and self._pWindowMenu: - - # Remove old window menu - pos = pMenuBar.FindMenu(_("&Window")) - if pos != wx.NOT_FOUND: - pMenuBar.Remove(pos) - - - def AddWindowMenu(self, pMenuBar): - - if pMenuBar and self._pWindowMenu: - - pos = pMenuBar.FindMenu(wx.GetStockLabel(wx.ID_HELP, wx.STOCK_NOFLAGS)) - if pos == wx.NOT_FOUND: - pMenuBar.Append(self._pWindowMenu, _("&Window")) - else: - pMenuBar.Insert(pos, self._pWindowMenu, _("&Window")) - - - def DoHandleMenu(self, event): - - evId = event.GetId() - - if evId == wxWINDOWCLOSE: - if self._pActiveChild: - self._pActiveChild.Close() - - elif evId == wxWINDOWCLOSEALL: - - while self._pActiveChild: - if not self._pActiveChild.Close(): - return # failure - - elif evId == wxWINDOWNEXT: - self.ActivateNext() - - elif evId == wxWINDOWPREV: - self.ActivatePrevious() - - else: - event.Skip() - - - def Tile(self, orient=wx.HORIZONTAL): - - client_window = self.GetClientWindow() - if not client_window: - raise Exception("Missing MDI Client Window") - - cur_idx = client_window.GetSelection() - if cur_idx == -1: - return - - if orient == wx.VERTICAL: - - client_window.Split(cur_idx, wx.LEFT) - - elif orient == wx.HORIZONTAL: - - client_window.Split(cur_idx, wx.TOP) - - -#----------------------------------------------------------------------------- -# AuiMDIChildFrame -#----------------------------------------------------------------------------- - -class AuiMDIChildFrame(wx.PyPanel): - - def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, - size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="AuiMDIChildFrame"): - - pClientWindow = parent.GetClientWindow() - if pClientWindow is None: - raise Exception("Missing MDI client window.") - - self.Init() - - # see comment in constructor - if style & wx.MINIMIZE: - self._activate_on_create = False - - cli_size = pClientWindow.GetClientSize() - - # create the window off-screen to prevent flicker - wx.PyPanel.__init__(self, pClientWindow, id, wx.Point(cli_size.x+1, cli_size.y+1), - size, wx.NO_BORDER, name=name) - - self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) - self.Show(False) - self.SetMDIParentFrame(parent) - - # this is the currently active child - parent.SetActiveChild(self) - self._title = title - - pClientWindow.AddPage(self, title, self._activate_on_create) - pClientWindow.Refresh() - - self.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuHighlight) - self.Bind(wx.EVT_ACTIVATE, self.OnActivate) - self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) - - - def Init(self): - - # There are two ways to create an tabbed mdi child fram without - # making it the active document. Either Show(False) can be called - # before Create() (as is customary on some ports with wxFrame-type - # windows), or wx.MINIMIZE can be passed in the style flags. Note that - # AuiMDIChildFrame is not really derived from wxFrame, as MDIChildFrame - # is, but those are the expected symantics. No style flag is passed - # onto the panel underneath. - - self._activate_on_create = True - - self._pMDIParentFrame = None - self._pMenuBar = None - - self._mdi_currect = None - self._mdi_newrect = wx.Rect() - self._icon = None - self._icon_bundle = None - - - def Destroy(self): - - pParentFrame = self.GetMDIParentFrame() - if not pParentFrame: - raise Exception("Missing MDI Parent Frame") - - pClientWindow = pParentFrame.GetClientWindow() - if not pClientWindow: - raise Exception("Missing MDI Client Window") - - if pParentFrame.GetActiveChild() == self: - - # deactivate ourself - event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, False, self.GetId()) - event.SetEventObject(self) - self.GetEventHandler().ProcessEvent(event) - - pParentFrame.SetActiveChild(None) - pParentFrame.SetChildMenuBar(None) - - for pos in xrange(pClientWindow.GetPageCount()): - if pClientWindow.GetPage(pos) == self: - return pClientWindow.DeletePage(pos) - - return False - - - def SetMenuBar(self, menu_bar): - - pOldMenuBar = self._pMenuBar - self._pMenuBar = menu_bar - - if self._pMenuBar: - - pParentFrame = self.GetMDIParentFrame() - if not pParentFrame: - raise Exception("Missing MDI Parent Frame") - - self._pMenuBar.Reparent(pParentFrame) - if pParentFrame.GetActiveChild() == self: - - # replace current menu bars - if pOldMenuBar: - pParentFrame.SetChildMenuBar(None) - - pParentFrame.SetChildMenuBar(self) - - - def GetMenuBar(self): - - return self._pMenuBar - - - def SetTitle(self, title): - - self._title = title - - pParentFrame = self.GetMDIParentFrame() - if not pParentFrame: - raise Exception("Missing MDI Parent Frame") - - pClientWindow = pParentFrame.GetClientWindow() - if pClientWindow is not None: - - for pos in xrange(pClientWindow.GetPageCount()): - if pClientWindow.GetPage(pos) == self: - pClientWindow.SetPageText(pos, self._title) - break - - - def GetTitle(self): - - return self._title - - - def SetIcons(self, icons): - - # get icon with the system icon size - self.SetIcon(icons.GetIcon(-1)) - self._icon_bundle = icons - - - def GetIcons(self): - - return self._icon_bundle - - - def SetIcon(self, icon): - - pParentFrame = self.GetMDIParentFrame() - if not pParentFrame: - raise Exception("Missing MDI Parent Frame") - - self._icon = icon - - bmp = wx.BitmapFromIcon(self._icon) - - pClientWindow = pParentFrame.GetClientWindow() - if pClientWindow is not None: - idx = pClientWindow.GetPageIndex(self) - if idx != -1: - pClientWindow.SetPageBitmap(idx, bmp) - - - def GetIcon(self): - - return self._icon - - - def Activate(self): - - pParentFrame = self.GetMDIParentFrame() - if not pParentFrame: - raise Exception("Missing MDI Parent Frame") - - pClientWindow = pParentFrame.GetClientWindow() - if pClientWindow is not None: - - for pos in xrange(pClientWindow.GetPageCount()): - if pClientWindow.GetPage(pos) == self: - pClientWindow.SetSelection(pos) - break - - - def OnMenuHighlight(self, event): - - if self._pMDIParentFrame: - - # we don't have any help text for this item, - # but may be the MDI frame does? - self._pMDIParentFrame.OnMenuHighlight(event) - - - def OnActivate(self, event): - - # do nothing - pass - - - def OnCloseWindow(self, event): - - pParentFrame = self.GetMDIParentFrame() - if pParentFrame: - if pParentFrame.GetActiveChild() == self: - - pParentFrame.SetActiveChild(None) - pParentFrame.SetChildMenuBar(None) - - pClientWindow = pParentFrame.GetClientWindow() - idx = pClientWindow.GetPageIndex(self) - - if idx != wx.NOT_FOUND: - pClientWindow.RemovePage(idx) - - self.Destroy() - - - def SetMDIParentFrame(self, parentFrame): - - self._pMDIParentFrame = parentFrame - - - def GetMDIParentFrame(self): - - return self._pMDIParentFrame - - - def CreateStatusBar(self, number=1, style=1, winid=1, name=""): - - return None - - - def GetStatusBar(self): - - return None - - - def SetStatusText(self, text, number=0): - - pass - - - def SetStatusWidths(self, widths_field): - - pass - - - # no toolbar bars - def CreateToolBar(self, style=1, winid=-1, name=""): - - return None - - - def GetToolBar(self): - - return None - - - # no maximize etc - def Maximize(self, maximize=True): - - pass - - - def Restore(self): - - pass - - - def Iconize(self, iconize=True): - - pass - - - def IsMaximized(self): - - return True - - - def IsIconized(self): - - return False - - - def ShowFullScreen(self, show=True, style=0): - - return False - - - def IsFullScreen(self): - - return False - - - def IsTopLevel(self): - - return False - - - # renamed from Show(). - def ActivateOnCreate(self, activate_on_create): - - self._activate_on_create = activate_on_create - return True - - - def Show(self, show=True): - - wx.PyPanel.Show(self, show) - - - def ApplyMDIChildFrameRect(self): - - if self._mdi_currect != self._mdi_newrect: - self.SetDimensions(*self._mdi_newrect) - self._mdi_currect = wx.Rect(*self._mdi_newrect) - - -#----------------------------------------------------------------------------- -# AuiMDIClientWindow -#----------------------------------------------------------------------------- - -class AuiMDIClientWindow(auibook.AuiNotebook): - - def __init__(self, parent, agwStyle=0): - - auibook.AuiNotebook.__init__(self, parent, wx.ID_ANY, wx.Point(0, 0), wx.Size(100, 100), - agwStyle=AUI_NB_DEFAULT_STYLE|wx.NO_BORDER) - - caption_icon_size = wx.Size(wx.SystemSettings.GetMetric(wx.SYS_SMALLICON_X), - wx.SystemSettings.GetMetric(wx.SYS_SMALLICON_Y)) - self.SetUniformBitmapSize(caption_icon_size) - - bkcolour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_APPWORKSPACE) - self.SetOwnBackgroundColour(bkcolour) - - self._mgr.GetArtProvider().SetColour(AUI_DOCKART_BACKGROUND_COLOUR, bkcolour) - - self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged) - self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnPageClose) - self.Bind(wx.EVT_SIZE, self.OnSize) - - - def SetSelection(self, nPage): - - return auibook.AuiNotebook.SetSelection(self, nPage) - - - def PageChanged(self, old_selection, new_selection): - - # don't do anything if the page doesn't actually change - if old_selection == new_selection: - return - - # notify old active child that it has been deactivated - if old_selection != -1 and old_selection < self.GetPageCount(): - - old_child = self.GetPage(old_selection) - if not old_child: - raise Exception("AuiMDIClientWindow.PageChanged - null page pointer") - - event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, False, old_child.GetId()) - event.SetEventObject(old_child) - old_child.GetEventHandler().ProcessEvent(event) - - # notify new active child that it has been activated - if new_selection != -1: - - active_child = self.GetPage(new_selection) - if not active_child: - raise Exception("AuiMDIClientWindow.PageChanged - null page pointer") - - event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, True, active_child.GetId()) - event.SetEventObject(active_child) - active_child.GetEventHandler().ProcessEvent(event) - - if active_child.GetMDIParentFrame(): - active_child.GetMDIParentFrame().SetActiveChild(active_child) - active_child.GetMDIParentFrame().SetChildMenuBar(active_child) - - - def OnPageClose(self, event): - - wnd = self.GetPage(event.GetSelection()) - wnd.Close() - - # regardless of the result of wnd.Close(), we've - # already taken care of the close operations, so - # suppress further processing - event.Veto() - - - def OnPageChanged(self, event): - - self.PageChanged(event.GetOldSelection(), event.GetSelection()) - - - def OnSize(self, event): - - auibook.AuiNotebook.OnSize(self, event) - - for pos in xrange(self.GetPageCount()): - self.GetPage(pos).ApplyMDIChildFrameRect() diff --git a/enaml/wx/wx_widget.py b/enaml/wx/wx_widget.py deleted file mode 100644 index 1487372ad..000000000 --- a/enaml/wx/wx_widget.py +++ /dev/null @@ -1,168 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.widgets.widget import ProxyWidget - -from .wx_layout_request import wxEvtLayoutRequested -from .wx_resource_helpers import get_cached_wxcolor, get_cached_wxfont -from .wx_toolkit_object import WxToolkitObject - - -class WxWidget(WxToolkitObject, ProxyWidget): - """ A Wx implementation of an Enaml ProxyWidget. - - """ - #: A reference to the toolkit widget created by the proxy. - widget = Typed(wx.Window) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def create_widget(self): - """ Creates the underlying wx.Window widget. - - """ - self.widget = wx.Window(self.parent_widget()) - - def init_widget(self): - """ Initialize the underlying widget. - - """ - super(WxWidget, self).init_widget() - d = self.declaration - if d.background: - self.set_background(d.background) - if d.foreground: - self.set_foreground(d.foreground) - if d.font: - self.set_font(d.font) - if -1 not in d.minimum_size: - self.set_minimum_size(d.minimum_size) - if -1 not in d.maximum_size: - self.set_maximum_size(d.maximum_size) - if d.tool_tip: - self.set_tool_tip(d.tool_tip) - if d.status_tip: - self.set_status_tip(d.status_tip) - self.set_enabled(d.enabled) - self.set_visible(d.visible) - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def post_wx_layout_request(self): - """ Post a wx layout request event to this widget's parent. - - This method should be called when the geometry of the widget has - changed and the layout system should update the layout. This will - post a wxEvtLayoutRequested event to the parent of this widget. - - """ - widget = self.widget - if widget: - parent = widget.GetParent() - if parent: - event = wxEvtLayoutRequested(widget.GetId()) - wx.PostEvent(parent, event) - - #-------------------------------------------------------------------------- - # ProxyWidget API - #-------------------------------------------------------------------------- - def set_minimum_size(self, min_size): - """ Sets the minimum size on the underlying widget. - - """ - self.widget.SetMinSize(wx.Size(*min_size)) - - def set_maximum_size(self, max_size): - """ Sets the maximum size on the underlying widget. - - """ - self.widget.SetMaxSize(wx.Size(*max_size)) - - def set_enabled(self, enabled): - """ Set the enabled state on the underlying widget. - - """ - self.widget.Enable(enabled) - - def set_visible(self, visible): - """ Set the visibility state on the underlying widget. - - """ - self.widget.Show(visible) - - def set_background(self, background): - """ Set the background color on the underlying widget. - - """ - if background is None: - wxcolor = wx.NullColour - else: - wxcolor = get_cached_wxcolor(background) - widget = self.widget - widget.SetBackgroundColour(wxcolor) - widget.Refresh() - - def set_foreground(self, foreground): - """ Set the foreground color on the underlying widget. - - """ - if foreground is None: - wxcolor = wx.NullColour - else: - wxcolor = get_cached_wxcolor(foreground) - widget = self.widget - widget.SetForegroundColour(wxcolor) - widget.Refresh() - - def set_font(self, font): - """ Set the font on the underlying widget. - - """ - if font is not None: - wxfont = get_cached_wxfont(font) - else: - index = wx.SYS_DEFAULT_GUI_FONT - wxfont = wx.SystemSettings.GetFont(index) - widget = self.widget - widget.SetFont(wxfont) - widget.Refresh() - - def set_tool_tip(self, tool_tip): - """ Set the tool tip of for this widget. - - """ - self.widget.SetToolTipString(tool_tip) - - def set_status_tip(self, status_tip): - """ This is not supported on Wx. - - """ - pass - - def ensure_visible(self): - """ Ensure the widget is visible. - - """ - self.widget.Show(True) - - def ensure_hidden(self): - """ Ensure the widget is hidden. - - """ - self.widget.Show(False) - - def restyle(self): - """ Stylesheets are not supported on Wx. - - """ - pass diff --git a/enaml/wx/wx_window.py b/enaml/wx/wx_window.py deleted file mode 100644 index d0d3fb746..000000000 --- a/enaml/wx/wx_window.py +++ /dev/null @@ -1,418 +0,0 @@ -#------------------------------------------------------------------------------ -# Copyright (c) 2013, Nucleic Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#------------------------------------------------------------------------------ -import wx - -from atom.api import Typed - -from enaml.layout.geometry import Pos, Rect, Size -from enaml.widgets.window import ProxyWindow, CloseEvent - -from .wx_action import wxAction -from .wx_container import WxContainer -from .wx_layout_request import EVT_COMMAND_LAYOUT_REQUESTED -from .wx_single_widget_sizer import wxSingleWidgetSizer -from .wx_widget import WxWidget - - -def finalize_close(d): - """ Finalize the closing of the declaration object. - - This is performed as a deferred call so that the window may fully - close before the declaration is potentially destroyed. - - """ - d.visible = False - d.closed() - if d.destroy_on_close: - d.destroy() - - -class wxCustomWindow(wx.Frame): - """ A custom wxFrame which manages a central widget. - - The window layout computes the min/max size of the window based - on its central widget, unless the user explicitly changes them. - - """ - def __init__(self, *args, **kwargs): - """ Initialize a wxCustomWindow. - - Parameters - ---------- - *args, **kwargs - The positional and keyword arguments needed to initialize - a wxFrame. - - """ - super(wxCustomWindow, self).__init__(*args, **kwargs) - self._central_widget = None - self.SetSizer(wxSingleWidgetSizer()) - self.Bind(wx.EVT_MENU, self.OnMenu) - self.Bind(wx.EVT_CLOSE, self.OnClose) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def OnMenu(self, event): - """ The event handler for the EVT_MENU event. - - This event handler will be called when an action is triggered - in a Menu or a ToolBar. - - """ - action = wxAction.FindById(event.GetId()) - if action is not None: - if action.IsCheckable(): - action.SetChecked(event.Checked()) - action.Trigger() - - def OnClose(self, event): - """ The event handler for the EVT_CLOSE event. - - This event handler prevents the frame from being destroyed on - close. Instead it just sets the visibility to False. - - """ - self.Hide() - - #-------------------------------------------------------------------------- - # Public API - #-------------------------------------------------------------------------- - def UpdateClientSizeHints(self): - """ Update the client size hints for the window. - - This will update the min and max sizes for the window according - to the current window state. This method is called automatically - when the central widget is changed. - - """ - sizer = self.GetSizer() - min_w, min_h = self.ClientToWindowSize(sizer.CalcMin()) - max_w, max_h = self.ClientToWindowSize(sizer.CalcMax()) - self.SetSizeHints(min_w, min_h, max_w, max_h) - cur_w, cur_h = self.GetSize() - new_w = min(max_w, max(min_w, cur_w)) - new_h = min(max_h, max(min_h, cur_h)) - if cur_w != new_w or cur_h != new_h: - self.SetSize(wx.Size(new_w, new_h)) - - def GetCentralWidget(self): - """ Returns the central widget for the window. - - Returns - ------- - result : wxWindow or None - The central widget of the window, or None if no widget - was provided. - - """ - return self._central_widget - - def SetCentralWidget(self, widget): - """ Set the central widget for this window. - - Parameters - ---------- - widget : wxWindow - The widget to use as the content of the window. - - """ - self._central_widget = widget - self.GetSizer().Add(widget) - self.UpdateClientSizeHints() - - -class WxWindow(WxWidget, ProxyWindow): - """ A Wx implementation of an Enaml ProxyWindow. - - """ - #: A reference tot he toolkit widget created by the proxy. - widget = Typed(wxCustomWindow) - - #-------------------------------------------------------------------------- - # Initialization API - #-------------------------------------------------------------------------- - def creation_style(self): - """ A convenience function for getting the creation style. - - """ - style = wx.DEFAULT_FRAME_STYLE - if self.declaration.always_on_top: - style |= wx.STAY_ON_TOP - return style - - def create_widget(self): - """ Create the underlying wxCustomWindow widget. - - """ - style = self.creation_style() - self.widget = wxCustomWindow(self.parent_widget(), style=style) - - def init_widget(self): - """ Initialize the window control. - - """ - super(WxWindow, self).init_widget() - d = self.declaration - if d.title: - self.set_title(d.title) - if -1 not in d.initial_size: - self.widget.SetClientSize(wx.Size(*d.initial_size)) - if -1 not in d.initial_position: - self.widget.Move(wx.Point(*d.initial_position)) - if d.icon: - self.set_icon(d.icon) - self.widget.Bind(wx.EVT_CLOSE, self.on_close) - - def init_layout(self): - """ Perform layout initialization for the control. - - """ - super(WxWindow, self).init_layout() - widget = self.widget - widget.SetCentralWidget(self.central_widget()) - widget.Bind(EVT_COMMAND_LAYOUT_REQUESTED, self.on_layout_requested) - - #-------------------------------------------------------------------------- - # Utility Methods - #-------------------------------------------------------------------------- - def central_widget(self): - """ Find and return the central widget child for this widget. - - Returns - ------- - result : wxWindow or None - The central widget defined for this widget, or None if one - is not defined. - - """ - d = self.declaration.central_widget() - if d is not None: - return d.proxy.widget or None - - #-------------------------------------------------------------------------- - # Child Events - #-------------------------------------------------------------------------- - def child_removed(self, child): - """ Handle the child removed event for a QtWindow. - - """ - if isinstance(child, WxContainer): - self.widget.SetCentralWidget(self.central_widget()) - - def child_added(self, child): - """ Handle the child added event for a QtWindow. - - """ - if isinstance(child, WxContainer): - self.widget.SetCentralWidget(self.central_widget()) - - #-------------------------------------------------------------------------- - # Event Handlers - #-------------------------------------------------------------------------- - def on_close(self, event): - """ The event handler for the EVT_CLOSE event. - - """ - d = self.declaration - d_event = CloseEvent() - d.closing(d_event) - if d_event.is_accepted(): - event.Skip() - # Make sure the frame is not modal when closing, or no other - # windows will be unblocked. - self.widget.MakeModal(False) - wx.CallAfter(finalize_close, d) - else: - event.Veto() - - def on_layout_requested(self, event): - """ Handle the layout request event from the central widget. - - """ - # wx likes to send events after the widget is destroyed. - if self.widget: - self.widget.UpdateClientSizeHints() - - #-------------------------------------------------------------------------- - # ProxyWindow API - #-------------------------------------------------------------------------- - def set_title(self, title): - """ Set the title of the window. - - """ - self.widget.SetTitle(title) - - def set_modality(self, modality): - """ Set the modality of the window. - - """ - if modality == 'non_modal': - self.widget.MakeModal(False) - else: - self.widget.MakeModal(True) - - def set_icon(self, icon): - """ This is not supported on Wx. - - """ - pass - - def position(self): - """ Get the position of the of the window. - - """ - point = self.widget.GetPosition() - return Pos(point.x, point.y) - - def set_position(self, pos): - """ Set the position of the window. - - """ - self.widget.SetPosition(wx.Point(*pos)) - - def size(self): - """ Get the size of the window. - - """ - size = self.widget.GetClientSize() - return Size(size.GetWidth(), size.GetHeight()) - - def set_size(self, size): - """ Set the size of the window. - - """ - size = wx.Size(*size) - if size.IsFullySpecified(): - self.widget.SetClientSize(size) - - def geometry(self): - """ Get the geometry of the window. - - """ - # Wx has no standard way of taking into account the size of - # the window frame. I'm not spending time on a workaround. - point = self.widget.GetPosition() - size = self.widget.GetClientSize() - return Rect(point.x, point.y, size.GetWidth(), size.GetHeight()) - - def set_geometry(self, rect): - """ Set the geometry of the window. - - """ - self.set_position(rect[:2]) - self.set_size(rect[2:]) - - def frame_geometry(self): - """ Get the geometry of the window. - - """ - r = self.widget.GetRect() - return Rect(r.GetX(), r.GetY(), r.GetWidth(), r.GetHeight()) - - def maximize(self): - """ Maximize the window. - - """ - self.widget.Maximize(True) - - def is_maximized(self): - """ Get whether the window is maximized. - - """ - return self.widget.IsMaximized() - - def minimize(self): - """ Minimize the window. - - """ - self.widget.Iconize(True) - - def is_minimized(self): - """ Get whether the window is minimized. - - """ - return self.widget.IsIconized() - - def restore(self): - """ Restore the window after a minimize or maximize. - - """ - self.widget.Maximize(False) - - def send_to_front(self): - """ Move the window to the top of the Z order. - - """ - self.widget.Raise() - - def send_to_back(self): - """ Move the window to the bottom of the Z order. - - """ - self.widget.Lower() - - def activate_window(self): - """ Activate the underlying window widget. - - """ - # wx makes no distinction between raise and activate - self.widget.Raise() - - def center_on_screen(self): - """ Center the window on the screen. - - """ - self.widget.CenterOnScreen() - - def center_on_widget(self, other): - """ Center the window on another widget. - - """ - widget = self.widget - rect = widget.GetRect() - geo = other.proxy.widget.GetScreenRect() - widget.Move(rect.CenterIn(geo).GetPosition()) - - def close(self): - """ Close the window - - """ - self.widget.Close() - - #-------------------------------------------------------------------------- - # Overrides - #-------------------------------------------------------------------------- - def set_visible(self, visible): - """ Set the visibility state on the underlying widget. - - This override sets the modality to false when hiding the window - and enabled it when showing the window (if requested). - - """ - modality = self.declaration.modality - self.widget.MakeModal(visible and modality != 'non_modal') - self.widget.Show(visible) - - def ensure_visible(self): - """ Ensure the widget is visible. - - This override forwards to the 'set_visible' method so that the - window modality is handled properly. - - """ - self.set_visible(True) - - def ensure_hidden(self): - """ Ensure the widget is hidden. - - This override forwards to the 'set_visible' method so that the - window modality is handled properly. - - """ - self.set_visible(False)