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""" Defines the range editor factory for all traits user interface toolkits. 18""" 19 20 21 22from types import CodeType 23 24 25 26from 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. 42from ..view import View 43 44from ..editor_factory import EditorFactory 45 46from ..toolkit import toolkit_object 47 48# ------------------------------------------------------------------------- 49# 'ToolkitEditorFactory' class: 50# ------------------------------------------------------------------------- 51 52 53class 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 cols = Range(1, 20) 63 64 #: Is user input set on every keystroke? 65 auto_set = Bool(True) 66 67 #: Is user input set when the Enter key is pressed? 68 enter_set = Bool(False) 69 70 #: Label for the low end of the range 71 low_label = Str() 72 73 #: Label for the high end of the range 74 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 label_width = Int() 79 80 #: The name of an [object.]trait that defines the low value for the range 81 low_name = Str() 82 83 #: The name of an [object.]trait that defines the high value for the range 84 high_name = Str() 85 86 #: Formatting string used to format value and labels 87 format = Str("%s") 88 89 #: Is the range for floating pointer numbers (vs. integers)? 90 is_float = Bool(Undefined) 91 92 #: Function to evaluate floats/ints when they are assigned to an object 93 #: trait 94 evaluate = Any() 95 96 #: The object trait containing the function used to evaluate floats/ints 97 evaluate_name = Str() 98 99 #: Low end of range 100 low = Property() 101 102 #: High end of range 103 high = Property() 104 105 #: Display mode to use 106 mode = Enum( 107 "auto", "slider", "xslider", "spinner", "enum", "text", "logslider" 108 ) 109 110 # ------------------------------------------------------------------------- 111 # Traits view definition: 112 # ------------------------------------------------------------------------- 113 114 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 def init(self, handler=None): 129 """ Performs any initialization needed after all constructor traits 130 have been set. 131 """ 132 if handler is not None: 133 if isinstance(handler, CTrait): 134 handler = handler.handler 135 136 if self.low_name == "": 137 if isinstance(handler._low, CodeType): 138 self.low = eval(handler._low) 139 else: 140 self.low = handler._low 141 142 if self.high_name == "": 143 if isinstance(handler._low, CodeType): 144 self.high = eval(handler._high) 145 else: 146 self.high = handler._high 147 else: 148 if (self.low is None) and (self.low_name == ""): 149 self.low = 0.0 150 151 if (self.high is None) and (self.high_name == ""): 152 self.high = 1.0 153 154 def _get_low(self): 155 return self._low 156 157 def _set_low(self, low): 158 old_low = self._low 159 self._low = low = self._cast(low) 160 if self.is_float is Undefined: 161 self.is_float = isinstance(low, float) 162 163 if (self.low_label == "") or ( 164 self.low_label == str(old_low) 165 ): 166 self.low_label = str(low) 167 168 def _get_high(self): 169 return self._high 170 171 def _set_high(self, high): 172 old_high = self._high 173 self._high = high = self._cast(high) 174 if self.is_float is Undefined: 175 self.is_float = isinstance(high, float) 176 177 if (self.high_label == "") or ( 178 self.high_label == str(old_high) 179 ): 180 self.high_label = str(high) 181 182 def _cast(self, value): 183 if not isinstance(value, str): 184 return value 185 186 try: 187 return int(value) 188 except ValueError: 189 return float(value) 190 191 # -- Private Methods ------------------------------------------------------ 192 193 def _get_low_high(self, ui): 194 """ Returns the low and high values used to determine the initial range. 195 """ 196 low, high = self.low, self.high 197 198 if (low is None) and (self.low_name != ""): 199 low = self.named_value(self.low_name, ui) 200 if self.is_float is Undefined: 201 self.is_float = isinstance(low, float) 202 203 if (high is None) and (self.high_name != ""): 204 high = self.named_value(self.high_name, ui) 205 if self.is_float is Undefined: 206 self.is_float = isinstance(high, float) 207 208 if self.is_float is Undefined: 209 self.is_float = True 210 211 return (low, high, self.is_float) 212 213 # ------------------------------------------------------------------------- 214 # Property getters. 215 # ------------------------------------------------------------------------- 216 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 low, high, is_float = self._low_value, self._high_value, self.is_float 230 231 if (low is None) or (high is None): 232 return toolkit_object("range_editor:RangeTextEditor") 233 234 if (not is_float) and (abs(high - low) > 1000000000): 235 return toolkit_object("range_editor:RangeTextEditor") 236 237 if self.mode != "auto": 238 return toolkit_object("range_editor:SimpleEditorMap")[self.mode] 239 240 if is_float and (abs(high - low) > 100): 241 return toolkit_object("range_editor:LargeRangeSliderEditor") 242 243 if is_float or (abs(high - low) <= 100): 244 return toolkit_object("range_editor:SimpleSliderEditor") 245 246 return toolkit_object("range_editor:SimpleSpinEditor") 247 248 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 low, high, is_float = self._low_value, self._high_value, self.is_float 262 if (low is None) or (high is None): 263 return toolkit_object("range_editor:RangeTextEditor") 264 265 if self.mode != "auto": 266 return toolkit_object("range_editor:CustomEditorMap")[self.mode] 267 268 if is_float or (abs(high - low) > 15): 269 return self.simple_editor_class 270 271 return toolkit_object("range_editor:CustomEnumEditor") 272 273 def _get_text_editor_class(self): 274 """Returns the editor class to use for a text style. 275 """ 276 return toolkit_object("range_editor:RangeTextEditor") 277 278 # ------------------------------------------------------------------------- 279 # 'Editor' factory methods: 280 # ------------------------------------------------------------------------- 281 282 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 self._low_value, self._high_value, self.is_float = self._get_low_high( 289 ui 290 ) 291 return super(RangeEditor, self).simple_editor( 292 ui, object, name, description, parent 293 ) 294 295 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 self._low_value, self._high_value, self.is_float = self._get_low_high( 302 ui 303 ) 304 return super(RangeEditor, self).custom_editor( 305 ui, object, name, description, parent 306 ) 307 308 309# Define the RangeEditor class 310RangeEditor = ToolkitEditorFactory 311