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/14/2004
15#
16# ------------------------------------------------------------------------------
17
18""" Defines common traits used within the traits.ui package.
19"""
20
21from pyface.ui_traits import (
22    Alignment,
23    Border,
24    HasBorder,
25    HasMargin,
26    Image,
27    Margin,
28    Position,
29    convert_bitmap,
30    convert_image,
31)
32from traits.api import (
33    Any,
34    Delegate,
35    Enum,
36    Expression,
37    Float,
38    HasStrictTraits,
39    List,
40    Range,
41    Str,
42    TraitError,
43    TraitType,
44)
45
46from .helper import PrefixList, SequenceTypes
47
48# -------------------------------------------------------------------------
49#  Trait definitions:
50# -------------------------------------------------------------------------
51
52# Orientation trait:
53Orientation = PrefixList(("vertical", "horizontal"))
54
55# Styles for user interface elements:
56EditorStyle = style_trait = PrefixList(
57    ("simple", "custom", "text", "readonly"), cols=4)
58
59# Group layout trait:
60Layout = PrefixList(("normal", "split", "tabbed", "flow", "fold"))
61
62# Trait for the default object being edited:
63AnObject = Expression("object")
64
65# The default dock style to use:
66DockStyle = dock_style_trait = Enum(
67    "fixed",
68    "horizontal",
69    "vertical",
70    "tab",
71    desc="the default docking style to use",
72)
73
74# The category of elements dragged out of the view:
75ExportType = Str(desc="the category of elements dragged out of the view")
76
77# Delegate a trait value to the object's **container** trait:
78ContainerDelegate = container_delegate = Delegate(
79    "container", listenable=False
80)
81
82# An identifier for the external help context:
83HelpId = help_id_trait = Str(desc="the external help context identifier")
84
85# A button to add to a view:
86AButton = Any()
87# AButton = Trait( '', Str, Instance( 'traitsui.menu.Action' ) )
88
89# The set of buttons to add to the view:
90Buttons = List(
91    AButton, desc="the action buttons to add to the bottom of the view"
92)
93
94# View trait specified by name or instance:
95AView = Any()
96# AView = Trait( '', Str, Instance( 'traitsui.view.View' ) )
97
98# FIXME: on AButton and AView: TraitCompound handlers with deferred-import
99# Instance traits are just broken. The Instance trait tries to update the
100# top-level CTrait's fast_validate table when the import is resolved. However,
101# sometimes the CTrait gets copied for unknown reasons and the copy's
102# fast_validate table is not updated although the TraitCompound's
103# slow_validates table is modified.
104
105# -------------------------------------------------------------------------
106#  'StatusItem' class:
107# -------------------------------------------------------------------------
108
109
110class StatusItem(HasStrictTraits):
111
112    #: The name of the trait the status information will be synched with:
113    name = Str("status")
114
115    #: The width of the status field. The possible values are:
116    #:
117    #:   - abs( width )  > 1.0: Width of the field in pixels = abs( width )
118    #:   - abs( width ) <= 1.0: Relative width of the field when compared to
119    #:                          the other relative width fields.
120    width = Float(0.5)
121
122    def __init__(self, value=None, **traits):
123        """ Initializes the item object.
124        """
125        super(StatusItem, self).__init__(**traits)
126
127        if value is not None:
128            self.name = value
129
130
131# -------------------------------------------------------------------------
132#  'ViewStatus' trait:
133# -------------------------------------------------------------------------
134
135
136class ViewStatus(TraitType):
137    """ Defines a trait whose value must be a single StatusItem instance or a
138        list of StatusItem instances.
139    """
140
141    #: Define the default value for the trait:
142    default_value = None
143
144    #: A description of the type of value this trait accepts:
145    info_text = (
146        "None, a string, a single StatusItem instance, or a list or "
147        "tuple of strings and/or StatusItem instances"
148    )
149
150    def validate(self, object, name, value):
151        """ Validates that a specified value is valid for this trait.
152        """
153        if isinstance(value, str):
154            return [StatusItem(name=value)]
155
156        if isinstance(value, StatusItem):
157            return [value]
158
159        if value is None:
160            return value
161
162        result = []
163        if isinstance(value, SequenceTypes):
164            for item in value:
165                if isinstance(item, str):
166                    result.append(StatusItem(name=item))
167                elif isinstance(item, StatusItem):
168                    result.append(item)
169                else:
170                    break
171            else:
172                return result
173
174        self.error(object, name, value)
175
176
177# -------------------------------------------------------------------------
178#  'ATheme' trait:
179# -------------------------------------------------------------------------
180
181
182def convert_theme(value, level=3):
183    """ Converts a specified value to a Theme if possible.
184    """
185    if not isinstance(value, str):
186        return value
187
188    if (value[:1] == "@") and (value.find(":") >= 2):
189        try:
190            from .image.image import ImageLibrary
191
192            info = ImageLibrary.image_info(value)
193        except:
194            info = None
195
196        if info is not None:
197            return info.theme
198
199    from .theme import Theme
200
201    return Theme(image=convert_image(value, level + 1))
202
203
204class ATheme(TraitType):
205    """ Defines a trait whose value must be a traits UI Theme or a string that
206        can be converted to one.
207    """
208
209    #: Define the default value for the trait:
210    default_value = None
211
212    #: A description of the type of value this trait accepts:
213    info_text = "a Theme or string that can be used to define one"
214
215    def __init__(self, value=None, **metadata):
216        """ Creates an ATheme trait.
217
218        Parameters
219        ----------
220        value : string or Theme
221            The default value for the ATheme, either a Theme object, or a
222            string from which a Theme object can be derived.
223        """
224        super(ATheme, self).__init__(convert_theme(value), **metadata)
225
226    def validate(self, object, name, value):
227        """ Validates that a specified value is valid for this trait.
228        """
229        from .theme import Theme
230
231        if value is None:
232            return None
233
234        new_value = convert_theme(value, 4)
235        if isinstance(new_value, Theme):
236            return new_value
237
238        self.error(object, name, value)
239
240
241# -------------------------------------------------------------------------------
242#  Other trait definitions:
243# -------------------------------------------------------------------------
244
245# The spacing between two items:
246Spacing = Range(-32, 32, 3)
247