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