1# ------------------------------------------------------------------------------ 2# 3# Copyright (c) 2005, Enthought, Inc. 4# All rights reserved. 5# 6# This software is provided without warranty under the terms of the BSD 7# license included in LICENSE.txt and may be redistributed only 8# under the conditions described in the aforementioned license. The license 9# is also available online at http://www.enthought.com/licenses/BSD.txt 10# 11# Thanks for using Enthought open source! 12# 13# Author: David C. Morrill 14# Date: 10/21/2004 15# 16# ------------------------------------------------------------------------------ 17 18""" Defines the various image enumeration editors for the wxPython user interface toolkit. 19""" 20 21 22import wx 23 24from traits.api import Any 25 26# FIXME: ToolkitEditorFactory is a proxy class defined here just for backward 27# compatibility. The class has been moved to the 28# traitsui.editors.image_enum_editor file. 29from traitsui.editors.image_enum_editor import ToolkitEditorFactory 30 31from .editor import Editor 32 33from .enum_editor import BaseEditor as BaseEnumEditor 34 35from .helper import bitmap_cache, position_window, TraitsUIPanel 36 37from .constants import WindowColor 38 39from .image_control import ImageControl 40 41from traitsui.wx import toolkit 42 43# ------------------------------------------------------------------------- 44# 'ReadonlyEditor' class: 45# ------------------------------------------------------------------------- 46 47 48class ReadonlyEditor(Editor): 49 """ Read-only style of image enumeration editor, which displays a single 50 ImageControl, representing the object trait's value. 51 """ 52 53 def init(self, parent): 54 """ Finishes initializing the editor by creating the underlying toolkit 55 widget. 56 """ 57 self.control = ImageControl( 58 parent, 59 bitmap_cache( 60 "%s%s%s" 61 % (self.factory.prefix, self.str_value, self.factory.suffix), 62 False, 63 self.factory._image_path, 64 ), 65 ) 66 67 def update_editor(self): 68 """ Updates the editor when the object trait changes externally to the 69 editor. 70 """ 71 self.control.Bitmap( 72 bitmap_cache( 73 "%s%s%s" 74 % (self.factory.prefix, self.str_value, self.factory.suffix), 75 False, 76 self.factory._image_path, 77 ) 78 ) 79 80 81class SimpleEditor(ReadonlyEditor): 82 """ Simple style of image enumeration editor, which displays an 83 ImageControl, representing the object trait's value. Clicking an image 84 displays a dialog box for selecting an image corresponding to a different 85 value. 86 """ 87 88 def init(self, parent): 89 """ Finishes initializing the editor by creating the underlying toolkit 90 widget. 91 """ 92 super(SimpleEditor, self).init(parent) 93 self.control.Selected(True) 94 self.control.Handler(self.popup_editor) 95 self.set_tooltip() 96 97 def popup_editor(self, control): 98 """ Handles the user clicking the ImageControl to display the pop-up 99 dialog. 100 """ 101 ImageEnumDialog(self) 102 103 104class CustomEditor(BaseEnumEditor): 105 """ Custom style of image enumeration editor, which displays a grid of 106 ImageControls. The user can click an image to select the corresponding 107 value. 108 """ 109 110 # ------------------------------------------------------------------------- 111 # Trait definitions: 112 # ------------------------------------------------------------------------- 113 114 update_handler = Any # Callback to call when any button clicked 115 116 def init(self, parent): 117 """ Finishes initializing the editor by creating the underlying toolkit 118 widget. 119 """ 120 super(CustomEditor, self).init(parent) 121 122 # Create the panel to hold the ImageControl buttons: 123 self.control = TraitsUIPanel(parent, -1) 124 self._create_image_grid() 125 126 def rebuild_editor(self): 127 # Clear any existing content: 128 self.control.SetSizer(None) 129 toolkit.destroy_children(self.control) 130 131 self._create_image_grid() 132 133 def _create_image_grid(self): 134 """ Populates a specified window with a grid of image buttons. 135 """ 136 panel = self.control 137 138 # Create the main sizer: 139 if self.factory.cols > 1: 140 sizer = wx.GridSizer(0, self.factory.cols, 0, 0) 141 else: 142 sizer = wx.BoxSizer(wx.VERTICAL) 143 144 # Add the set of all possible choices: 145 factory = self.factory 146 cur_value = self.value 147 for name in self.names: 148 value = self.mapping[name] 149 control = ImageControl( 150 panel, 151 bitmap_cache( 152 "%s%s%s" % (factory.prefix, name, factory.suffix), 153 False, 154 factory._image_path, 155 ), 156 value == cur_value, 157 self.update_object, 158 ) 159 control.value = value 160 sizer.Add(control, 0, wx.ALL, 2) 161 self.set_tooltip(control) 162 163 # Finish setting up the control layout: 164 panel.SetSizerAndFit(sizer) 165 166 def update_object(self, control): 167 """ Handles the user clicking on an ImageControl to set an object value. 168 """ 169 self.value = control.value 170 if self.update_handler is not None: 171 self.update_handler() 172 173 def update_editor(self): 174 """ Updates the editor when the object trait changes externally to the 175 editor. 176 """ 177 value = self.value 178 for control in self.control.GetChildren(): 179 control.Selected(value == control.value) 180 181 182class ImageEnumDialog(wx.Frame): 183 """ Dialog box for selecting an ImageControl 184 """ 185 186 def __init__(self, editor): 187 """ Initializes the object. 188 """ 189 wx.Frame.__init__(self, editor.control, -1, "", style=wx.SIMPLE_BORDER) 190 self.SetBackgroundColour(WindowColor) 191 self.Bind(wx.EVT_ACTIVATE, self._on_close_dialog) 192 self._closed = False 193 194 dlg_editor = CustomEditor( 195 self, 196 factory=editor.factory, 197 ui=editor.ui, 198 object=editor.object, 199 name=editor.name, 200 description=editor.description, 201 update_handler=self._close_dialog, 202 ) 203 204 dlg_editor.init(self) 205 206 # Wrap the dialog around the image button panel: 207 sizer = wx.BoxSizer(wx.VERTICAL) 208 sizer.Add(dlg_editor.control) 209 sizer.Fit(self) 210 211 # Position the dialog: 212 position_window(self, parent=editor.control) 213 self.Show() 214 215 def _on_close_dialog(self, event): 216 """ Closes the dialog. 217 """ 218 if not event.GetActive(): 219 self._close_dialog() 220 221 def _close_dialog(self): 222 """ Closes the dialog. 223 """ 224 if not self._closed: 225 self._closed = True 226 self.Destroy() 227