Repository URL to install this package:
Version:
7.2.1 ▾
|
# (C) Copyright 2004-2021 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
""" Creates a wxPython user interface for a specified UI object.
"""
import wx
from pyface.api import SystemMetrics
from .helper import save_window, TraitsUIScrolledPanel
from .ui_base import BaseDialog
from .ui_panel import panel
from .constants import DefaultTitle, WindowColor, scrollbar_dx
from traitsui.menu import (
ApplyButton,
RevertButton,
OKButton,
CancelButton,
HelpButton,
)
def ui_modal(ui, parent):
""" Creates a modal wxPython user interface for a specified UI object.
"""
_ui_dialog(ui, parent, BaseDialog.MODAL)
def ui_nonmodal(ui, parent):
""" Creates a non-modal wxPython user interface for a specified UI object.
"""
_ui_dialog(ui, parent, BaseDialog.NONMODAL)
def _ui_dialog(ui, parent, style):
""" Creates a wxPython dialog box for a specified UI object.
Changes are not immediately applied to the underlying object. The user must
click **Apply** or **OK** to apply changes. The user can revert changes by
clicking **Revert** or **Cancel**.
"""
if ui.owner is None:
ui.owner = ModalDialog()
BaseDialog.display_ui(ui, parent, style)
class ModalDialog(BaseDialog):
""" Modal dialog box for Traits-based user interfaces.
"""
def init(self, ui, parent, style):
self.is_modal = style == self.MODAL
style = 0
view = ui.view
if view.resizable:
style |= wx.RESIZE_BORDER
title = view.title
if title == "":
title = DefaultTitle
revert = apply = False
window = ui.control
if window is not None:
window.SetSizer(None)
ui.reset()
if hasattr(self, "revert"):
revert = self.revert.IsEnabled()
if hasattr(self, "apply"):
apply = self.apply.IsEnabled()
else:
self.ui = ui
if self.is_modal:
window = wx.Dialog(
parent, -1, title, style=style | wx.DEFAULT_DIALOG_STYLE
)
else:
window = wx.Frame(
parent,
-1,
title,
style=style
| (wx.DEFAULT_FRAME_STYLE & (~wx.RESIZE_BORDER)),
)
window.SetBackgroundColour(WindowColor)
self.control = window
self.set_icon(view.icon)
window.Bind(wx.EVT_CLOSE, self._on_close_page)
window.Bind(wx.EVT_CHAR, self._on_key)
# Create the 'context' copies we will need while editing:
context = ui.context
ui._context = context
ui.context = self._copy_context(context)
ui._revert = self._copy_context(context)
# Create the actual trait sheet panel and imbed it in a scrollable
# window (if requested):
sw_sizer = wx.BoxSizer(wx.VERTICAL)
if ui.scrollable:
sizer = wx.BoxSizer(wx.VERTICAL)
sw = TraitsUIScrolledPanel(window)
trait_sheet = panel(ui, sw)
sizer.Add(trait_sheet, 1, wx.EXPAND | wx.ALL, 4)
tsdx, tsdy = trait_sheet.GetSize()
tsdx += 8
tsdy += 8
sw.SetScrollRate(16, 16)
max_dy = (2 * SystemMetrics().screen_height) // 3
sw.SetSizer(sizer)
sw.SetSize(
wx.Size(
tsdx + ((tsdy > max_dy) * scrollbar_dx), min(tsdy, max_dy)
)
)
else:
sw = panel(ui, window)
sw_sizer.Add(sw, 1, wx.EXPAND)
buttons = [self.coerce_button(button) for button in view.buttons]
nbuttons = len(buttons)
if (nbuttons != 1) or (not self.is_button(buttons[0], "")):
# Create the necessary special function buttons:
sw_sizer.Add(wx.StaticLine(window, -1), 0, wx.EXPAND)
b_sizer = wx.BoxSizer(wx.HORIZONTAL)
if nbuttons == 0:
if view.apply:
self.check_button(buttons, ApplyButton)
if view.revert:
self.check_button(buttons, RevertButton)
if view.ok:
self.check_button(buttons, OKButton)
if view.cancel:
self.check_button(buttons, CancelButton)
if view.help:
self.check_button(buttons, HelpButton)
for raw_button, button in zip(view.buttons, buttons):
default = raw_button == view.default_button
if self.is_button(button, "Apply"):
self.apply = self.add_button(
button, b_sizer, self._on_apply, apply, default=default
)
ui.observe(
self._on_applyable, "modified", dispatch="ui"
)
elif self.is_button(button, "Revert"):
self.revert = self.add_button(
button,
b_sizer,
self._on_revert,
revert,
default=default,
)
elif self.is_button(button, "OK"):
self.ok = self.add_button(
button, b_sizer, self._on_ok, default=default
)
ui.observe(self._on_error, "errors", dispatch="ui")
elif self.is_button(button, "Cancel"):
self.add_button(
button, b_sizer, self._on_cancel, default=default
)
elif self.is_button(button, "Help"):
self.add_button(
button, b_sizer, self._on_help, default=default
)
elif not self.is_button(button, ""):
self.add_button(button, b_sizer, default=default)
sw_sizer.Add(b_sizer, 0, wx.ALIGN_RIGHT | wx.ALL, 5)
# Add the menu bar, tool bar and status bar (if any):
self.add_menubar()
self.add_toolbar()
self.add_statusbar()
# Lay all of the dialog contents out:
window.SetSizerAndFit(sw_sizer)
def close(self, rc=wx.ID_OK):
""" Closes the dialog window.
"""
ui = self.ui
ui.result = rc == wx.ID_OK
save_window(ui)
if self.is_modal:
self.control.EndModal(rc)
self.control.Unbind(wx.EVT_CLOSE)
self.control.Unbind(wx.EVT_CHAR)
ui.finish()
self.ui = self.apply = self.revert = self.help = self.control = None
def _copy_context(self, context):
""" Creates a copy of a *context* dictionary.
"""
result = {}
for name, value in context.items():
if value is not None:
result[name] = value.clone_traits()
else:
result[name] = None
return result
def _apply_context(self, from_context, to_context):
""" Applies the traits in the *from_context* to the *to_context*.
"""
for name, value in from_context.items():
if value is not None:
to_context[name].copy_traits(value)
else:
to_context[name] = None
if to_context is self.ui._context:
on_apply = self.ui.view.on_apply
if on_apply is not None:
on_apply()
def _on_close_page(self, event):
""" Handles the user clicking the window/dialog "close" button/icon.
"""
if self.ui.view.close_result:
self._on_ok(event)
else:
self._on_cancel(event)
def _on_ok(self, event=None):
""" Closes the window and saves changes (if allowed by the handler).
"""
if self.ui.handler.close(self.ui.info, True):
self._apply_context(self.ui.context, self.ui._context)
self.close(wx.ID_OK)
def _on_cancel(self, event=None):
""" Closes the window and discards changes (if allowed by the handler).
"""
if self.ui.handler.close(self.ui.info, False):
self._apply_context(self.ui._revert, self.ui._context)
self.close(wx.ID_CANCEL)
def _on_key(self, event):
""" Handles the user pressing the Escape key.
"""
if event.GetKeyCode() == 0x1B:
self._on_close_page(event)
def _on_apply(self, event):
""" Handles a request to apply changes.
"""
ui = self.ui
self._apply_context(ui.context, ui._context)
if hasattr(self, "revert"):
self.revert.Enable(True)
ui.handler.apply(ui.info)
ui.modified = False
def _on_revert(self, event):
""" Handles a request to revert changes.
"""
ui = self.ui
self._apply_context(ui._revert, ui.context)
self._apply_context(ui._revert, ui._context)
self.revert.Enable(False)
ui.handler.revert(ui.info)
ui.modified = False
def _on_applyable(self, event):
""" Handles a change to the "modified" state of the user interface .
"""
state = event.new
self.apply.Enable(state)
def _on_error(self, event):
""" Handles editing errors.
"""
errors = event.new
self.ok.Enable(errors == 0)