1
|
|
# ------------------------------------------------------------------------------
|
2
|
|
#
|
3
|
|
# Copyright (c) 2008, 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
|
11
|
""" Defines the range editor factory for all traits user interface toolkits.
|
18
|
|
"""
|
19
|
|
|
20
|
|
|
21
|
|
|
22
|
11
|
from types import CodeType
|
23
|
|
|
24
|
|
|
25
|
|
|
26
|
11
|
from traits.api import (
|
27
|
|
CTrait,
|
28
|
|
Property,
|
29
|
|
Range,
|
30
|
|
Enum,
|
31
|
|
Str,
|
32
|
|
Int,
|
33
|
|
Any,
|
34
|
|
Str,
|
35
|
|
Bool,
|
36
|
|
Undefined,
|
37
|
|
)
|
38
|
|
|
39
|
|
# CIRCULAR IMPORT FIXME: Importing from the source rather than traits.ui.api
|
40
|
|
# to avoid circular imports, as this EditorFactory will be part of
|
41
|
|
# traits.ui.api as well.
|
42
|
11
|
from ..view import View
|
43
|
|
|
44
|
11
|
from ..editor_factory import EditorFactory
|
45
|
|
|
46
|
11
|
from ..toolkit import toolkit_object
|
47
|
|
|
48
|
|
# -------------------------------------------------------------------------
|
49
|
|
# 'ToolkitEditorFactory' class:
|
50
|
|
# -------------------------------------------------------------------------
|
51
|
|
|
52
|
|
|
53
|
11
|
class ToolkitEditorFactory(EditorFactory):
|
54
|
|
""" Editor factory for range editors.
|
55
|
|
"""
|
56
|
|
|
57
|
|
# -------------------------------------------------------------------------
|
58
|
|
# Trait definitions:
|
59
|
|
# -------------------------------------------------------------------------
|
60
|
|
|
61
|
|
#: Number of columns when displayed as an enumeration
|
62
|
11
|
cols = Range(1, 20)
|
63
|
|
|
64
|
|
#: Is user input set on every keystroke?
|
65
|
11
|
auto_set = Bool(True)
|
66
|
|
|
67
|
|
#: Is user input set when the Enter key is pressed?
|
68
|
11
|
enter_set = Bool(False)
|
69
|
|
|
70
|
|
#: Label for the low end of the range
|
71
|
11
|
low_label = Str()
|
72
|
|
|
73
|
|
#: Label for the high end of the range
|
74
|
11
|
high_label = Str()
|
75
|
|
|
76
|
|
#: FIXME: This is supported only in the wx backend so far.
|
77
|
|
#: The width of the low and high labels
|
78
|
11
|
label_width = Int()
|
79
|
|
|
80
|
|
#: The name of an [object.]trait that defines the low value for the range
|
81
|
11
|
low_name = Str()
|
82
|
|
|
83
|
|
#: The name of an [object.]trait that defines the high value for the range
|
84
|
11
|
high_name = Str()
|
85
|
|
|
86
|
|
#: Formatting string used to format value and labels
|
87
|
11
|
format = Str("%s")
|
88
|
|
|
89
|
|
#: Is the range for floating pointer numbers (vs. integers)?
|
90
|
11
|
is_float = Bool(Undefined)
|
91
|
|
|
92
|
|
#: Function to evaluate floats/ints when they are assigned to an object
|
93
|
|
#: trait
|
94
|
11
|
evaluate = Any()
|
95
|
|
|
96
|
|
#: The object trait containing the function used to evaluate floats/ints
|
97
|
11
|
evaluate_name = Str()
|
98
|
|
|
99
|
|
#: Low end of range
|
100
|
11
|
low = Property()
|
101
|
|
|
102
|
|
#: High end of range
|
103
|
11
|
high = Property()
|
104
|
|
|
105
|
|
#: Display mode to use
|
106
|
11
|
mode = Enum(
|
107
|
|
"auto", "slider", "xslider", "spinner", "enum", "text", "logslider"
|
108
|
|
)
|
109
|
|
|
110
|
|
# -------------------------------------------------------------------------
|
111
|
|
# Traits view definition:
|
112
|
|
# -------------------------------------------------------------------------
|
113
|
|
|
114
|
11
|
traits_view = View(
|
115
|
|
[
|
116
|
|
["low", "high", "|[Range]"],
|
117
|
|
["low_label{Low}", "high_label{High}", "|[Range Labels]"],
|
118
|
|
[
|
119
|
|
"auto_set{Set automatically}",
|
120
|
|
"enter_set{Set on enter key pressed}",
|
121
|
|
"is_float{Is floating point range}",
|
122
|
|
"-[Options]>",
|
123
|
|
],
|
124
|
|
["cols", "|[Number of columns for integer custom style]<>"],
|
125
|
|
]
|
126
|
|
)
|
127
|
|
|
128
|
11
|
def init(self, handler=None):
|
129
|
|
""" Performs any initialization needed after all constructor traits
|
130
|
|
have been set.
|
131
|
|
"""
|
132
|
11
|
if handler is not None:
|
133
|
11
|
if isinstance(handler, CTrait):
|
134
|
0
|
handler = handler.handler
|
135
|
|
|
136
|
11
|
if self.low_name == "":
|
137
|
11
|
if isinstance(handler._low, CodeType):
|
138
|
0
|
self.low = eval(handler._low)
|
139
|
|
else:
|
140
|
0
|
self.low = handler._low
|
141
|
|
|
142
|
11
|
if self.high_name == "":
|
143
|
11
|
if isinstance(handler._low, CodeType):
|
144
|
0
|
self.high = eval(handler._high)
|
145
|
|
else:
|
146
|
0
|
self.high = handler._high
|
147
|
|
else:
|
148
|
11
|
if (self.low is None) and (self.low_name == ""):
|
149
|
0
|
self.low = 0.0
|
150
|
|
|
151
|
11
|
if (self.high is None) and (self.high_name == ""):
|
152
|
0
|
self.high = 1.0
|
153
|
|
|
154
|
11
|
def _get_low(self):
|
155
|
11
|
return self._low
|
156
|
|
|
157
|
11
|
def _set_low(self, low):
|
158
|
11
|
old_low = self._low
|
159
|
11
|
self._low = low = self._cast(low)
|
160
|
11
|
if self.is_float is Undefined:
|
161
|
11
|
self.is_float = isinstance(low, float)
|
162
|
|
|
163
|
11
|
if (self.low_label == "") or (
|
164
|
|
self.low_label == str(old_low)
|
165
|
|
):
|
166
|
11
|
self.low_label = str(low)
|
167
|
|
|
168
|
11
|
def _get_high(self):
|
169
|
11
|
return self._high
|
170
|
|
|
171
|
11
|
def _set_high(self, high):
|
172
|
11
|
old_high = self._high
|
173
|
11
|
self._high = high = self._cast(high)
|
174
|
11
|
if self.is_float is Undefined:
|
175
|
0
|
self.is_float = isinstance(high, float)
|
176
|
|
|
177
|
11
|
if (self.high_label == "") or (
|
178
|
|
self.high_label == str(old_high)
|
179
|
|
):
|
180
|
11
|
self.high_label = str(high)
|
181
|
|
|
182
|
11
|
def _cast(self, value):
|
183
|
11
|
if not isinstance(value, str):
|
184
|
11
|
return value
|
185
|
|
|
186
|
0
|
try:
|
187
|
0
|
return int(value)
|
188
|
0
|
except ValueError:
|
189
|
0
|
return float(value)
|
190
|
|
|
191
|
|
# -- Private Methods ------------------------------------------------------
|
192
|
|
|
193
|
11
|
def _get_low_high(self, ui):
|
194
|
|
""" Returns the low and high values used to determine the initial range.
|
195
|
|
"""
|
196
|
8
|
low, high = self.low, self.high
|
197
|
|
|
198
|
11
|
if (low is None) and (self.low_name != ""):
|
199
|
0
|
low = self.named_value(self.low_name, ui)
|
200
|
11
|
if self.is_float is Undefined:
|
201
|
0
|
self.is_float = isinstance(low, float)
|
202
|
|
|
203
|
11
|
if (high is None) and (self.high_name != ""):
|
204
|
0
|
high = self.named_value(self.high_name, ui)
|
205
|
11
|
if self.is_float is Undefined:
|
206
|
0
|
self.is_float = isinstance(high, float)
|
207
|
|
|
208
|
11
|
if self.is_float is Undefined:
|
209
|
0
|
self.is_float = True
|
210
|
|
|
211
|
8
|
return (low, high, self.is_float)
|
212
|
|
|
213
|
|
# -------------------------------------------------------------------------
|
214
|
|
# Property getters.
|
215
|
|
# -------------------------------------------------------------------------
|
216
|
11
|
def _get_simple_editor_class(self):
|
217
|
|
""" Returns the editor class to use for a simple style.
|
218
|
|
|
219
|
|
The type of editor depends on the type and extent of the range being
|
220
|
|
edited:
|
221
|
|
|
222
|
|
* One end of range is unspecified: RangeTextEditor
|
223
|
|
* **mode** is specified and not 'auto': editor corresponding to **mode**
|
224
|
|
* Floating point range with extent > 100: LargeRangeSliderEditor
|
225
|
|
* Integer range or floating point range with extent <= 100:
|
226
|
|
SimpleSliderEditor
|
227
|
|
* All other cases: SimpleSpinEditor
|
228
|
|
"""
|
229
|
8
|
low, high, is_float = self._low_value, self._high_value, self.is_float
|
230
|
|
|
231
|
11
|
if (low is None) or (high is None):
|
232
|
0
|
return toolkit_object("range_editor:RangeTextEditor")
|
233
|
|
|
234
|
11
|
if (not is_float) and (abs(high - low) > 1000000000):
|
235
|
0
|
return toolkit_object("range_editor:RangeTextEditor")
|
236
|
|
|
237
|
11
|
if self.mode != "auto":
|
238
|
8
|
return toolkit_object("range_editor:SimpleEditorMap")[self.mode]
|
239
|
|
|
240
|
11
|
if is_float and (abs(high - low) > 100):
|
241
|
0
|
return toolkit_object("range_editor:LargeRangeSliderEditor")
|
242
|
|
|
243
|
11
|
if is_float or (abs(high - low) <= 100):
|
244
|
0
|
return toolkit_object("range_editor:SimpleSliderEditor")
|
245
|
|
|
246
|
0
|
return toolkit_object("range_editor:SimpleSpinEditor")
|
247
|
|
|
248
|
11
|
def _get_custom_editor_class(self):
|
249
|
|
""" Creates a custom style of range editor
|
250
|
|
|
251
|
|
The type of editor depends on the type and extent of the range being
|
252
|
|
edited:
|
253
|
|
|
254
|
|
* One end of range is unspecified: RangeTextEditor
|
255
|
|
* **mode** is specified and not 'auto': editor corresponding to **mode**
|
256
|
|
* Floating point range: Same as "simple" style
|
257
|
|
* Integer range with extent > 15: Same as "simple" style
|
258
|
|
* Integer range with extent <= 15: CustomEnumEditor
|
259
|
|
|
260
|
|
"""
|
261
|
8
|
low, high, is_float = self._low_value, self._high_value, self.is_float
|
262
|
11
|
if (low is None) or (high is None):
|
263
|
0
|
return toolkit_object("range_editor:RangeTextEditor")
|
264
|
|
|
265
|
11
|
if self.mode != "auto":
|
266
|
8
|
return toolkit_object("range_editor:CustomEditorMap")[self.mode]
|
267
|
|
|
268
|
11
|
if is_float or (abs(high - low) > 15):
|
269
|
0
|
return self.simple_editor_class
|
270
|
|
|
271
|
0
|
return toolkit_object("range_editor:CustomEnumEditor")
|
272
|
|
|
273
|
11
|
def _get_text_editor_class(self):
|
274
|
|
"""Returns the editor class to use for a text style.
|
275
|
|
"""
|
276
|
0
|
return toolkit_object("range_editor:RangeTextEditor")
|
277
|
|
|
278
|
|
# -------------------------------------------------------------------------
|
279
|
|
# 'Editor' factory methods:
|
280
|
|
# -------------------------------------------------------------------------
|
281
|
|
|
282
|
11
|
def simple_editor(self, ui, object, name, description, parent):
|
283
|
|
""" Generates an editor using the "simple" style.
|
284
|
|
Overridden to set the values of the _low_value, _high_value and
|
285
|
|
is_float traits.
|
286
|
|
|
287
|
|
"""
|
288
|
8
|
self._low_value, self._high_value, self.is_float = self._get_low_high(
|
289
|
|
ui
|
290
|
|
)
|
291
|
8
|
return super(RangeEditor, self).simple_editor(
|
292
|
|
ui, object, name, description, parent
|
293
|
|
)
|
294
|
|
|
295
|
11
|
def custom_editor(self, ui, object, name, description, parent):
|
296
|
|
""" Generates an editor using the "custom" style.
|
297
|
|
Overridden to set the values of the _low_value, _high_value and
|
298
|
|
is_float traits.
|
299
|
|
|
300
|
|
"""
|
301
|
8
|
self._low_value, self._high_value, self.is_float = self._get_low_high(
|
302
|
|
ui
|
303
|
|
)
|
304
|
8
|
return super(RangeEditor, self).custom_editor(
|
305
|
|
ui, object, name, description, parent
|
306
|
|
)
|
307
|
|
|
308
|
|
|
309
|
|
# Define the RangeEditor class
|
310
|
11
|
RangeEditor = ToolkitEditorFactory
|