def _add_groups(self, content, outer): """Adds a list of Group objects to the panel, creating a layout if needed. Return the outermost layout. """ # Use the existing layout if there is one. if outer is None: if self.horizontal: outer = HorizontalLayout() else: outer = VerticalLayout() outer.setSizeUndefined() # Process each group. for subgroup in content: panel = _GroupPanel(subgroup, self.ui).control if isinstance(panel, IComponent): outer.addComponent(panel) else: # The sub-group is empty which seems to be used as a way of # providing some whitespace. outer.addComponent(Label(' ')) return outer
def _add_items(self, content, outer=None): """Adds a list of Item objects, creating a layout if needed. Return the outermost layout. """ # Get local references to various objects we need: ui = self.ui info = ui.info handler = ui.handler group = self.group show_left = group.show_left padding = group.padding columns = group.columns # See if a label is needed. show_labels = False for item in content: show_labels |= item.show_label # See if a grid layout is needed. if show_labels or columns > 1: inner = GridLayout(columns * 2, len(content)) inner.setSpacing(True) inner.setSizeUndefined() if outer is None: outer = inner else: outer.addComponent(inner) row = 0 if show_left: label_alignment = Alignment.MIDDLE_RIGHT else: label_alignment = Alignment.MIDDLE_LEFT else: # Use the existing layout if there is one. if outer is None: if self.horizontal: outer = HorizontalLayout() else: outer = VerticalLayout() outer.setSizeUndefined() inner = outer row = -1 label_alignment = 0 # Process each Item in the list: col = -1 for item in content: # Keep a track of the current logical row and column unless the # layout is not a grid. col += 1 if row >= 0 and col >= columns: col = 0 row += 1 # Get the name in order to determine its type: name = item.name # Check if is a label: if name == '': label = item.label if label != "": # Create the label widget. if item.style == 'simple': label = Label(label) else: label = heading_text(None, text=label).control self._add_widget(inner, label, row, col, show_labels) if item.emphasized: self._add_emphasis(label) # Continue on to the next Item in the list: continue # Check if it is a separator: if name == '_': cols = columns # See if the layout is a grid. if row >= 0: # Move to the start of the next row if necessary. if col > 0: col = 0 row += 1 # # Skip the row we are about to do. # row += 1 # Allow for the columns. if show_labels: cols *= 2 for i in range(cols): if self.horizontal: # Add a vertical separator: line = Panel() line.setWidth('2px') line.setHeight('-1px') if row < 0: inner.addComponent(line) else: inner.addComponent(line, row, i) else: # Add a horizontal separator: line = Label('<hr />', Label.CONTENT_XHTML) line.setWidth('100%') # FIXME: explicit container size if row < 0: inner.addComponent(line) else: inner.addComponent(line, i, row) # Continue on to the next Item in the list: continue # Convert a blank to a 5 pixel spacer: if name == ' ': name = '5' # Check if it is a spacer: if all_digits.match( name ): # If so, add the appropriate amount of space to the layout: spacer = Label('') if self.horizontal: # Add a horizontal spacer: spacer.setWidth(name + 'px') else: # Add a vertical spacer: spacer.setHeight(name + 'px') self._add_widget(inner, spacer, row, col, show_labels) # Continue on to the next Item in the list: continue # Otherwise, it must be a trait Item: object = eval( item.object_, globals(), ui.context ) trait = object.base_trait( name ) desc = trait.desc or '' fixed_width = False # Handle any label. if item.show_label: label = self._create_label(item, ui, desc) self._add_widget(inner, label, row, col, show_labels, label_alignment) else: label = None # Get the editor factory associated with the Item: editor_factory = item.editor if editor_factory is None: editor_factory = trait.get_editor() # If still no editor factory found, use a default text editor: if editor_factory is None: from text_editor import ToolkitEditorFactory editor_factory = ToolkitEditorFactory() # If the item has formatting traits set them in the editor # factory: if item.format_func is not None: editor_factory.format_func = item.format_func if item.format_str != '': editor_factory.format_str = item.format_str # If the item has an invalid state extended trait name, set it # in the editor factory: if item.invalid != '': editor_factory.invalid = item.invalid # Create the requested type of editor from the editor factory: factory_method = getattr( editor_factory, item.style + '_editor' ) editor = factory_method( ui, object, name, item.tooltip, None).set( item = item, object_name = item.object ) # Tell the editor to actually build the editing widget. Note that # "inner" is a layout. This shouldn't matter as individual editors # shouldn't be using it as a parent anyway. The important thing is # that it is not None (otherwise the main TraitsUI code can change # the "kind" of the created UI object). editor.prepare(inner) control = editor.control # Set the initial 'enabled' state of the editor from the factory: editor.enabled = editor_factory.enabled # Add emphasis to the editor control if requested: if item.emphasized: self._add_emphasis(control) # Give the editor focus if it requested it: if item.has_focus: control.focus() # Set the correct size on the control, as specified by the user: stretch = 0 scrollable = editor.scrollable item_width = item.width item_height = item.height if (item_width != -1) or (item_height != -1): is_horizontal = self.horizontal min_size = control.minimumSizeHint() width = min_size.width() height = min_size.height() if (0.0 < item_width <= 1.0) and is_horizontal: stretch = int(100 * item_width) item_width = int(item_width) if item_width < -1: item_width = -item_width else: item_width = max(item_width, width) if (0.0 < item_height <= 1.0) and (not is_horizontal): stretch = int(100 * item_height) item_height = int(item_height) if item_height < -1: item_height = -item_height else: item_height = max(item_height, height) control.setWidth(max(item_width, 0)) control.setHeight(max(item_height, 0)) # Bind the editor into the UIInfo object name space so it can be # referred to by a Handler while the user interface is active: Id = item.id or name info.bind( Id, editor, item.id ) # Also, add the editors to the list of editors used to construct # the user interface: ui._editors.append( editor ) # If the handler wants to be notified when the editor is created, # add it to the list of methods to be called when the UI is # complete: defined = getattr( handler, Id + '_defined', None ) if defined is not None: ui.add_defined( defined ) # If the editor is conditionally visible, add the visibility # 'expression' and the editor to the UI object's list of monitored # objects: if item.visible_when != '': ui.add_visible( item.visible_when, editor ) # If the editor is conditionally enabled, add the enabling # 'expression' and the editor to the UI object's list of monitored # objects: if item.enabled_when != '': ui.add_enabled( item.enabled_when, editor ) # Add the created editor control to the layout with the appropriate # size and stretch policies: ui._scrollable |= scrollable # item_resizable = ((item.resizable is True) or # ((item.resizable is Undefined) and scrollable)) # if item_resizable: # stretch = stretch or 50 # self.resizable = True # elif item.springy: # stretch = stretch or 50 # policy = control.sizePolicy() # if self.horizontal: # policy.setHorizontalStretch(stretch) # if item_resizable or item.springy: # policy.setHorizontalPolicy(QtGui.QSizePolicy.Expanding) # else: # policy.setVerticalStretch(stretch) # if item_resizable or item.springy: # policy.setVerticalPolicy(QtGui.QSizePolicy.Expanding) # control.setSizePolicy(policy) # FIXME: Need to decide what to do about border_size and padding self._add_widget(inner, control, row, col, show_labels) # Save the reference to the label control (if any) in the editor: editor.label_control = label return outer
def __init__(self, group, ui, suppress_label=False): """Initialise the object. """ # Get the contents of the group: content = group.get_content() # Save these for other methods. self.group = group self.ui = ui if group.orientation == 'horizontal': self.horizontal = True else: self.horizontal = False # outer is the top-level widget or layout that will eventually be # returned. sub is the TabSheet or Accordion corresponding to any # 'tabbed' or 'fold' layout. It is only used to collapse nested # widgets. inner is the object (not necessarily a layout) that new # controls should be added to. outer = sub = inner = None # Get the group label. if suppress_label: label = "" else: label = group.label # Create a border if requested. if group.show_border: outer = Panel(label) if self.horizontal: inner = HorizontalLayout() else: inner = VerticalLayout() inner.setSizeUndefined() inner.addComponent(outer) elif label != "": if self.horizontal: outer = inner = HorizontalLayout() else: outer = inner = VerticalLayout() inner.setSizeUndefined() inner.addComponent(heading_text(None, text=label).control) # Add the layout specific content. if len(content) == 0: pass elif group.layout == 'flow': raise NotImplementedError, "the 'flow' layout isn't implemented" elif group.layout == 'split': # Create the splitter. splitter = _GroupSplitter(group) if self.horizontal: splitter.setOrientation(SplitPanel.ORIENTATION_HORIZONTAL) else: splitter.setOrientation(SplitPanel.ORIENTATION_VERTICAL) if outer is None: outer = splitter else: inner.addComponent(splitter) # Create an editor. editor = SplitterGroupEditor(control=outer, splitter=splitter, ui=ui) self._setup_editor(group, editor) self._add_splitter_items(content, splitter) elif group.layout in ('tabbed', 'fold'): # Create the TabSheet or Accordion. if group.layout == 'tabbed': sub = TabSheet() else: sub = Accordion() _fill_panel(sub, content, self.ui, self._add_page_item) if outer is None: outer = sub else: inner.addComponent(sub) # Create an editor. editor = TabbedFoldGroupEditor(container=sub, control=outer, ui=ui) self._setup_editor(group, editor) else: # See if we need to control the visual appearence of the group. if group.visible_when != '' or group.enabled_when != '': # Make sure that outer is a widget or a layout. if outer is None: outer = inner = HorizontalLayout() outer.setSizeUndefined() # Create an editor. self._setup_editor(group, GroupEditor(control=outer)) if isinstance(content[0], Group): layout = self._add_groups(content, inner) else: layout = self._add_items(content, inner) # for c in layout.getComponentIterator(): # layout.setComponentAlignment(c, Alignment.TOP_LEFT) if outer is None: outer = layout elif layout is not inner: inner.addComponent(layout) # Publish the top-level widget, layout or None. self.control = outer # Publish the optional sub-control. self.sub_control = sub