1
#------------------------------------------------------------------------------
3
# Copyright (c) 2005, Enthought, Inc.
6
# This software is provided without warranty under the terms of the BSD
7
# license included in enthought/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
11
# Thanks for using Enthought open source!
13
# Author: David C. Morrill
16
#------------------------------------------------------------------------------
18
""" Defines the View class used to represent the structural content of a
19
Traits-based user interface.
22
#-------------------------------------------------------------------------------
24
#-------------------------------------------------------------------------------
26
from __future__ import absolute_import
28
from traits.api import (Any, Bool, Callable, Enum, Event, Float, Instance, List, Str,
29
Trait, TraitPrefixList)
31
from .view_element import ViewElement, ViewSubElement
35
from .ui_traits import (AButton, ATheme, AnObject, Buttons, DockStyle,
36
EditorStyle, ExportType, HelpId, Image, SequenceTypes, ViewStatus)
38
from .handler import Handler, default_handler
40
from .group import Group
42
from .item import Item
44
from .include import Include
46
#-------------------------------------------------------------------------------
48
#-------------------------------------------------------------------------------
50
# Name of the view trait:
51
AnId = Str( desc = 'the name of the view' )
53
# Contents of the view trait (i.e., a single Group object):
54
Content = Instance( Group, desc = 'the content of the view' )
56
# An optional model/view factory for converting the model into a viewable
58
AModelView = Callable( desc = 'the factory function for converting a model '
59
'into a model/view object' )
61
# Reference to a Handler object trait:
62
AHandler = Any( desc = 'the handler for the view' )
64
# Dialog window title trait:
65
ATitle = Str( desc = 'the window title for the view' )
67
# Dialog window icon trait
68
#icon_trait = Instance( 'pyface.image_resource.ImageResource',
69
# desc = 'the ImageResource of the icon file for the view' )
71
# User interface 'kind' trait. The values have the following meanings:
73
# * 'panel': An embeddable panel. This type of window is intended to be used as
74
# part of a larger interface.
75
# * 'subpanel': An embeddable panel that does not display command buttons,
76
# even if the View specifies them.
77
# * 'modal': A modal dialog box that operates on a clone of the object until
78
# the user commits the change.
79
# * 'nonmodal': A nonmodal dialog box that operates on a clone of the object
80
# until the user commits the change
81
# * 'live': A nonmodal dialog box that immediately updates the object.
82
# * 'livemodal': A modal dialog box that immediately updates the object.
83
# * 'popup': A temporary, frameless popup dialog that immediately updates the
84
# object and is active only while the mouse pointer is in the dialog.
85
# * 'info': A temporary, frameless popup dialog that immediately updates the
86
# object and is active only while the dialog is still over the invoking
88
# * 'wizard': A wizard modal dialog box. A wizard contains a sequence of
89
# pages, which can be accessed by clicking **Next** and **Back** buttons.
90
# Changes to attribute values are applied only when the user clicks the
91
# **Finish** button on the last page.
92
AKind = Trait( 'live', TraitPrefixList(
93
'panel', 'subpanel', 'modal', 'nonmodal', 'livemodal',
94
'live', 'popup', 'popover', 'info', 'wizard' ),
95
desc = 'the kind of view window to create',
98
# Apply changes handler:
99
OnApply = Callable( desc = 'the routine to call when modal changes are applied '
102
# Is the dialog window resizable?
103
IsResizable = Bool( False, desc = 'whether dialog can be resized or not' )
105
# Is the view scrollable?
106
IsScrollable = Bool( False, desc = 'whether view should be scrollable or not' )
108
# The valid categories of imported elements that can be dragged into the view:
109
ImportTypes = List( Str, desc = 'the categories of elements that can be '
110
'dragged into the view' )
112
# The view position and size traits:
113
Width = Float( -1E6, desc = 'the width of the view window' )
114
Height = Float( -1E6, desc = 'the height of the view window' )
115
XCoordinate = Float( -1E6, desc = 'the x coordinate of the view window' )
116
YCoordinate = Float( -1E6, desc = 'the y coordinate of the view window' )
118
# The result that should be returned if the user clicks the window or dialog
119
# close button or icon
120
CloseResult = Enum( None, True, False,
121
desc = 'the result to return when the user clicks the '
122
'window or dialog close button or icon' )
124
# The KeyBindings trait:
125
AKeyBindings = Instance( 'traitsui.key_bindings.KeyBindings',
126
desc = 'the global key bindings for the view' )
128
#-------------------------------------------------------------------------------
130
#-------------------------------------------------------------------------------
132
class View ( ViewElement ):
133
""" A Traits-based user interface for one or more objects.
135
The attributes of the View object determine the contents and layout of
136
an attribute-editing window. A View object contains a set of Group,
137
Item, and Include objects. A View object can be an attribute of an
138
object derived from HasTraits, or it can be a standalone object.
141
#---------------------------------------------------------------------------
143
#---------------------------------------------------------------------------
145
# A unique identifier for the view:
148
# The top-level Group object for the view:
151
# The menu bar for the view. Usually requires a custom **handler**:
152
menubar = Any # Instance( pyface.action.MenuBarManager )
154
# The toolbar for the view. Usually requires a custom **handler**:
155
toolbar = Any # Instance( pyface.action.ToolBarManager )
157
# Status bar items to add to the view's status bar. The value can be:
159
# - **None**: No status bar for the view (the default).
160
# - string: Same as [ StatusItem( name = string ) ].
161
# - StatusItem: Same as [ StatusItem ].
162
# - [ [StatusItem|string], ... ]: Create a status bar with one field for
163
# each StatusItem in the list (or tuple). The status bar fields are
164
# defined from left to right in the order specified. A string value is
165
# converted to: StatusItem( name = string ):
166
statusbar = ViewStatus
168
# List of button actions to add to the view. The **traitsui.menu**
169
# module defines standard buttons, such as **OKButton**, and standard sets
170
# of buttons, such as **ModalButtons**, which can be used to define a value
171
# for this attribute. This value can also be a list of button name strings,
172
# such as ``['OK', 'Cancel', 'Help']``. If set to the empty list, the
173
# view contains a default set of buttons (equivalent to **LiveButtons**:
174
# Undo/Redo, Revert, OK, Cancel, Help). To suppress buttons in the view,
175
# use the **NoButtons** variable, defined in **traitsui.menu**.
178
# The default button to activate when Enter is pressed. If not specified,
179
# pressing Enter will not activate any button.
180
default_button = AButton
182
# The set of global key bindings for the view. Each time a key is pressed
183
# while the view has keyboard focus, the key is checked to see if it is one
184
# of the keys recognized by the KeyBindings object. If it is, the matching
185
# KeyBinding's method name is checked to see if it is defined on any of the
186
# object's in the view's context. If it is, the method is invoked. If the
187
# result of the method is **False**, then the search continues with the
188
# next object in the context. If any invoked method returns a non-False
189
# value, processing stops and the key is marked as having been handled. If
190
# all invoked methods return **False**, or no matching KeyBinding object is
191
# found, the key is processed normally. If the view has a non-empty *id*
192
# trait, the contents of the **KeyBindings** object will be saved as part
193
# of the view's persistent data:
194
key_bindings = AKeyBindings
196
# The Handler object that provides GUI logic for handling events in the
197
# window. Set this attribute only if you are using a custom Handler. If
198
# not set, the default Traits UI Handler is used.
201
# The factory function for converting a model into a model/view object:
202
model_view = AModelView
204
# Title for the view, displayed in the title bar when the view appears as a
205
# secondary window (i.e., dialog or wizard). If not specified, "Edit
206
# properties" is used as the title.
209
# The name of the icon to display in the dialog window title bar:
212
# The kind of user interface to create:
215
# The default object being edited:
218
# The default editor style of elements in the view:
221
# The default docking style to use for sub-groups of the view. The following
222
# values are possible:
224
# * 'fixed': No rearrangement of sub-groups is allowed.
225
# * 'horizontal': Moveable elements have a visual "handle" to the left by
226
# which the element can be dragged.
227
# * 'vertical': Moveable elements have a visual "handle" above them by
228
# which the element can be dragged.
229
# * 'tabbed': Moveable elements appear as tabbed pages, which can be
230
# arranged within the window or "stacked" so that only one appears at
234
# The image to display on notebook tabs:
237
# Called when modal changes are applied or reverted:
240
# Can the user resize the window?
241
resizable = IsResizable
243
# Can the user scroll the view? If set to True, window-level scroll bars
244
# appear whenever the window is too small to show all of its contents at
245
# one time. If set to False, the window does not scroll, but individual
246
# widgets might still contain scroll bars.
247
scrollable = IsScrollable
249
# The category of exported elements:
252
# The valid categories of imported elements:
253
imports = ImportTypes
255
# External help context identifier, which can be used by a custom help
256
# handler. This attribute is ignored by the default help handler.
259
# Requested x-coordinate (horizontal position) for the view window. This
260
# attribute can be specified in the following ways:
262
# * A positive integer: indicates the number of pixels from the left edge
263
# of the screen to the left edge of the window.
264
# * A negative integer: indicates the number of pixels from the right edge
265
# of the screen to the right edge of the window.
266
# * A floating point value between 0 and 1: indicates the fraction of the
267
# total screen width between the left edge of the screen and the left edge
269
# * A floating point value between -1 and 0: indicates the fraction of the
270
# total screen width between the right edge of the screen and the right
271
# edge of the window.
274
# Requested y-coordinate (vertical position) for the view window. This
275
# attribute behaves exactly like the **x** attribute, except that its value
276
# indicates the position of the top or bottom of the view window relative
277
# to the top or bottom of the screen.
280
# Requested width for the view window, as an (integer) number of pixels, or
281
# as a (floating point) fraction of the screen width.
284
# Requested height for the view window, as an (integer) number of pixels, or
285
# as a (floating point) fraction of the screen height.
288
# Class of dropped objects that can be added:
291
# Event when the view has been updated:
294
# What result should be returned if the user clicks the window or dialog
295
# close button or icon?
296
close_result = CloseResult
298
# The default theme to use for a contained item:
301
# The default theme to use for a contained item's label:
304
# Note: Group objects delegate their 'object' and 'style' traits to the View
306
#-- Deprecated Traits (DO NOT USE) -----------------------------------------
309
cancel = Bool( False )
312
apply = Bool( False )
313
revert = Bool( False )
316
#---------------------------------------------------------------------------
317
# Initializes the object:
318
#---------------------------------------------------------------------------
320
def __init__ ( self, *values, **traits ):
321
""" Initializes the object.
323
ViewElement.__init__( self, **traits )
324
self.set_content( *values )
326
#---------------------------------------------------------------------------
327
# Sets the content of a view:
328
#---------------------------------------------------------------------------
330
def set_content ( self, *values ):
331
""" Sets the content of a view.
336
if isinstance( value, ViewSubElement ):
337
content.append( value )
338
elif type( value ) in SequenceTypes:
339
content.append( Group( *value ) )
340
elif (isinstance( value, basestring ) and
341
(value[:1] == '<') and (value[-1:] == '>')):
342
# Convert string to an Include value:
343
content.append( Include( value[1:-1].strip() ) )
345
content.append( Item( value ) )
347
# If there are any 'Item' objects in the content, wrap the content in a
350
if isinstance( item, Item ):
351
content = [ Group( *content ) ]
354
# Wrap all of the content up into a Group and save it as our content:
355
self.content = Group( container = self, *content )
357
#---------------------------------------------------------------------------
358
# Creates a UI user interface object:
359
#---------------------------------------------------------------------------
361
def ui ( self, context, parent = None, kind = None,
362
view_elements = None, handler = None,
363
id = '', scrollable = None,
365
""" Creates a **UI** object, which generates the actual GUI window or
366
panel from a set of view elements.
370
context : object or dictionary
371
A single object or a dictionary of string/object pairs, whose trait
372
attributes are to be edited. If not specified, the current object is
374
parent : window component
375
The window parent of the View object's window
377
The kind of window to create. See the **AKind** trait for details.
378
If *kind* is unspecified or None, the **kind** attribute of the
380
view_elements : ViewElements object
381
The set of Group, Item, and Include objects contained in the view.
382
Do not use this parameter when calling this method directly.
383
handler : Handler object
384
A handler object used for event handling in the dialog box. If
385
None, the default handler for Traits UI is used.
387
A unique ID for persisting preferences about this user interface,
388
such as size and position. If not specified, no user preferences
391
Indicates whether the dialog box should be scrollable. When set to
392
True, scroll bars appear on the dialog box if it is not large enough
393
to display all of the items in the view at one time.
396
handler = handler or self.handler or default_handler()
397
if not isinstance( handler, Handler ):
401
handler.set( **args )
403
if not isinstance( context, dict ):
404
context = context.trait_context()
406
context.setdefault( 'handler', handler )
407
handler = context[ 'handler' ]
409
if self.model_view is not None:
410
context[ 'object' ] = self.model_view( context[ 'object' ] )
415
id = '%s:%s' % ( self_id, id )
419
if scrollable is None:
420
scrollable = self.scrollable
422
ui = UI( view = self,
425
view_elements = view_elements,
428
scrollable = scrollable )
433
ui.ui( parent, kind )
437
#---------------------------------------------------------------------------
438
# Replaces any items which have an 'id' with an Include object with the
439
# same 'id', and puts the object with the 'id' into the specified
440
# ViewElements object:
441
#---------------------------------------------------------------------------
443
def replace_include ( self, view_elements ):
444
""" Replaces any items that have an ID with an Include object with
445
the same ID, and puts the object with the ID into the specified
448
if self.content is not None:
449
self.content.replace_include( view_elements )
451
#---------------------------------------------------------------------------
452
# Returns a 'pretty print' version of the View:
453
#---------------------------------------------------------------------------
455
def __repr__ ( self ):
456
""" Returns a "pretty print" version of the View.
458
if self.content is None:
460
return "( %s )" % ', '.join(
461
[ item.__repr__() for item in self.content.content ] )