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.direction = QtGui.QBoxLayout.LeftToRight else: self.direction = QtGui.QBoxLayout.TopToBottom # outer is the top-level widget or layout that will eventually be # returned. sub is the QTabWidget or QToolBox 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 = QtGui.QGroupBox(label) inner = QtGui.QBoxLayout(self.direction, outer) elif label != "": outer = inner = QtGui.QBoxLayout(self.direction) inner.addWidget(ui_panel.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 = ui_panel._GroupSplitter(group) splitter.setOpaqueResize(False) # Mimic wx backend resize behavior if self.direction == QtGui.QBoxLayout.TopToBottom: splitter.setOrientation(QtCore.Qt.Vertical) # Make sure the splitter will expand to fill available space policy = splitter.sizePolicy() policy.setHorizontalStretch(50) policy.setVerticalStretch(50) if group.orientation == 'horizontal': policy.setVerticalPolicy(QtGui.QSizePolicy.Expanding) else: policy.setHorizontalPolicy(QtGui.QSizePolicy.Expanding) splitter.setSizePolicy(policy) if outer is None: outer = splitter else: inner.addWidget(splitter) # Create an editor. editor = ui_panel.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 TabWidget or ToolBox. if group.layout == 'tabbed': sub = QtGui.QTabWidget() sub.setProperty("traits_tabbed_group", True) else: sub = QtGui.QToolBox() # Give tab/tool widget stretch factor equivalent to default stretch # factory for a resizeable item. See end of '_add_items'. policy = sub.sizePolicy() policy.setHorizontalStretch(50) policy.setVerticalStretch(50) sub.setSizePolicy(policy) ui_panel._fill_panel(sub, content, self.ui, self._add_page_item) if outer is None: outer = sub else: inner.addWidget(sub) # Create an editor. editor = ui_panel.TabbedFoldGroupEditor(container=sub, control=outer, ui=ui) self._setup_editor(group, editor) else: # See if we need to control the visual appearance of the group. if group.visible_when != '' or group.enabled_when != '': # Make sure that outer is a widget and inner is a layout. # Hiding a layout is not properly supported by Qt (the # workaround in ``traitsui.qt4.editor._visible_changed_helper`` # often leaves undesirable blank space). if outer is None: outer = inner = QtGui.QBoxLayout(self.direction) if isinstance(outer, QtGui.QLayout): widget = QtGui.QWidget() widget.setLayout(outer) outer = widget # Create an editor. self._setup_editor(group, ui_panel.GroupEditor(control=outer)) if isinstance(content[0], Group): layout = self._add_groups(content, inner) else: layout = self._add_items(content, inner) layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) if outer is None: outer = layout elif layout is not inner: inner.addLayout(layout) if group.style_sheet: if isinstance(outer, QtGui.QLayout): inner = outer outer = QtGui.QWidget() outer.setLayout(inner) # ensure this is not empty group if isinstance(outer, QtGui.QWidget): outer.setStyleSheet(group.style_sheet) # Publish the top-level widget, layout or None. self.control = outer # Publish the optional sub-control. self.sub_control = sub
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 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 = QtGui.QGridLayout() if outer is None: outer = inner else: outer.addLayout(inner) row = 0 if show_left: label_alignment = QtCore.Qt.AlignRight else: label_alignment = QtCore.Qt.AlignLeft else: # Use the existing layout if there is one. if outer is None: outer = QtGui.QBoxLayout(self.direction) 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 = QtGui.QLabel(label) else: label = ui_panel.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): line = QtGui.QFrame() if self.direction == QtGui.QBoxLayout.LeftToRight: # Add a vertical separator: line.setFrameShape(QtGui.QFrame.VLine) if row < 0: inner.addWidget(line) else: inner.addWidget(line, i, row) else: # Add a horizontal separator: line.setFrameShape(QtGui.QFrame.HLine) if row < 0: inner.addWidget(line) else: inner.addWidget(line, row, i) line.setFrameShadow(QtGui.QFrame.Sunken) # 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 ui_panel.all_digits.match(name): # If so, add the appropriate amount of space to the layout: n = int(name) if self.direction == QtGui.QBoxLayout.LeftToRight: # Add a horizontal spacer: spacer = QtGui.QSpacerItem(n, 1) else: # Add a vertical spacer: spacer = QtGui.QSpacerItem(1, n) 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 '' # Get the editor factory associated with the Item: editor_factory = item.editor if editor_factory is None: editor_factory = trait.get_editor().set(**item.editor_args) # If still no editor factory found, use a default text editor: if editor_factory is None: from traitsui.qt4.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 if item.style_sheet: control.setStyleSheet(item.style_sheet) # Set the initial 'enabled' state of the editor from the factory: editor.enabled = editor_factory.enabled # 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 editor.label_control = label # 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.setFocus() # Set the correct size on the control, as specified by the user: stretch = 0 item_width = item.width item_height = item.height if (item_width != -1) or (item_height != -1): is_horizontal = (self.direction == QtGui.QBoxLayout.LeftToRight) min_size = control.minimumSizeHint() width = min_size.width() height = min_size.height() force_width = False force_height = False 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 force_width = True 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 force_height = True else: item_height = max(item_height, height) control.setMinimumWidth(max(item_width, 0)) control.setMinimumHeight(max(item_height, 0)) if (stretch == 0 or not is_horizontal) and force_width: control.setMaximumWidth(item_width) if (stretch == 0 or is_horizontal) and force_height: control.setMaximumHeight(item_height) # Set size and stretch policies self._set_item_size_policy(editor, item, label, stretch) # Add the created editor control to the layout # FIXME: Need to decide what to do about border_size and padding self._add_widget(inner, control, row, col, show_labels) # ---- Update the UI object # 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) self.ui._scrollable |= editor.scrollable # 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) 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.direction = QtGui.QBoxLayout.LeftToRight else: self.direction = QtGui.QBoxLayout.TopToBottom # outer is the top-level widget or layout that will eventually be # returned. sub is the QTabWidget or QToolBox 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 = QtGui.QGroupBox(label) inner = QtGui.QBoxLayout(self.direction, outer) elif label != "": outer = inner = QtGui.QBoxLayout(self.direction) inner.addWidget(ui_panel.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 = ui_panel._GroupSplitter(group) splitter.setOpaqueResize(False) # Mimic wx backend resize behavior if self.direction == QtGui.QBoxLayout.TopToBottom: splitter.setOrientation(QtCore.Qt.Vertical) # Make sure the splitter will expand to fill available space policy = splitter.sizePolicy() policy.setHorizontalStretch(50) policy.setVerticalStretch(50) if group.orientation == "horizontal": policy.setVerticalPolicy(QtGui.QSizePolicy.Expanding) else: policy.setHorizontalPolicy(QtGui.QSizePolicy.Expanding) splitter.setSizePolicy(policy) if outer is None: outer = splitter else: inner.addWidget(splitter) # Create an editor. editor = ui_panel.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 TabWidget or ToolBox. if group.layout == "tabbed": sub = QtGui.QTabWidget() sub.setProperty("traits_tabbed_group", True) else: sub = QtGui.QToolBox() # Give tab/tool widget stretch factor equivalent to default stretch # factory for a resizeable item. See end of '_add_items'. policy = sub.sizePolicy() policy.setHorizontalStretch(50) policy.setVerticalStretch(50) sub.setSizePolicy(policy) ui_panel._fill_panel(sub, content, self.ui, self._add_page_item) if outer is None: outer = sub else: inner.addWidget(sub) # Create an editor. editor = ui_panel.TabbedFoldGroupEditor(container=sub, control=outer, ui=ui) self._setup_editor(group, editor) else: # See if we need to control the visual appearance of the group. if group.visible_when != "" or group.enabled_when != "": # Make sure that outer is a widget and inner is a layout. # Hiding a layout is not properly supported by Qt (the # workaround in ``traitsui.qt4.editor._visible_changed_helper`` # often leaves undesirable blank space). if outer is None: outer = inner = QtGui.QBoxLayout(self.direction) if isinstance(outer, QtGui.QLayout): widget = QtGui.QWidget() widget.setLayout(outer) outer = widget # Create an editor. self._setup_editor(group, ui_panel.GroupEditor(control=outer)) if isinstance(content[0], Group): layout = self._add_groups(content, inner) else: layout = self._add_items(content, inner) layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) if outer is None: outer = layout elif layout is not inner: inner.addLayout(layout) if group.style_sheet: if isinstance(outer, QtGui.QLayout): inner = outer outer = QtGui.QWidget() outer.setLayout(inner) # ensure this is not empty group if isinstance(outer, QtGui.QWidget): outer.setStyleSheet(group.style_sheet) # Publish the top-level widget, layout or None. self.control = outer # Publish the optional sub-control. self.sub_control = sub
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 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 = QtGui.QGridLayout() if outer is None: outer = inner else: outer.addLayout(inner) row = 0 if show_left: label_alignment = QtCore.Qt.AlignRight else: label_alignment = QtCore.Qt.AlignLeft else: # Use the existing layout if there is one. if outer is None: outer = QtGui.QBoxLayout(self.direction) 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 = QtGui.QLabel(label) else: label = ui_panel.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): line = QtGui.QFrame() if self.direction == QtGui.QBoxLayout.LeftToRight: # Add a vertical separator: line.setFrameShape(QtGui.QFrame.VLine) if row < 0: inner.addWidget(line) else: inner.addWidget(line, i, row) else: # Add a horizontal separator: line.setFrameShape(QtGui.QFrame.HLine) if row < 0: inner.addWidget(line) else: inner.addWidget(line, row, i) line.setFrameShadow(QtGui.QFrame.Sunken) # 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 ui_panel.all_digits.match(name): # If so, add the appropriate amount of space to the layout: n = int(name) if self.direction == QtGui.QBoxLayout.LeftToRight: # Add a horizontal spacer: spacer = QtGui.QSpacerItem(n, 1) else: # Add a vertical spacer: spacer = QtGui.QSpacerItem(1, n) 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 "" # Get the editor factory associated with the Item: editor_factory = item.editor if editor_factory is None: editor_factory = trait.get_editor().set(**item.editor_args) # If still no editor factory found, use a default text editor: if editor_factory is None: from traitsui.qt4.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 if item.style_sheet: control.setStyleSheet(item.style_sheet) # Set the initial 'enabled' state of the editor from the factory: editor.enabled = editor_factory.enabled # 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 editor.label_control = label # 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.setFocus() # Set the correct size on the control, as specified by the user: stretch = 0 item_width = item.width item_height = item.height if (item_width != -1) or (item_height != -1): is_horizontal = self.direction == QtGui.QBoxLayout.LeftToRight min_size = control.minimumSizeHint() width = min_size.width() height = min_size.height() force_width = False force_height = False 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 force_width = True 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 force_height = True else: item_height = max(item_height, height) control.setMinimumWidth(max(item_width, 0)) control.setMinimumHeight(max(item_height, 0)) if (stretch == 0 or not is_horizontal) and force_width: control.setMaximumWidth(item_width) if (stretch == 0 or is_horizontal) and force_height: control.setMaximumHeight(item_height) # Set size and stretch policies self._set_item_size_policy(editor, item, label, stretch) # Add the created editor control to the layout # FIXME: Need to decide what to do about border_size and padding self._add_widget(inner, control, row, col, show_labels) # ---- Update the UI object # 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) self.ui._scrollable |= editor.scrollable # 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) return outer
def __init__(self, ui, parent, is_subpanel): """Initialise the object. """ self.ui = ui history = ui.history view = ui.view # Reset any existing history listeners. if history is not None: history.on_trait_change(self._on_undoable, 'undoable', remove=True) history.on_trait_change(self._on_redoable, 'redoable', remove=True) history.on_trait_change(self._on_revertable, 'undoable', remove=True) # Determine if we need any buttons or an 'undo' history. buttons = [self.coerce_button(button) for button in view.buttons] nr_buttons = len(buttons) has_buttons = (not is_subpanel and (nr_buttons != 1 or not self.is_button(buttons[0], ''))) if nr_buttons == 0: if view.undo: self.check_button(buttons, UndoButton) if view.revert: self.check_button(buttons, RevertButton) if view.help: self.check_button(buttons, HelpButton) if not is_subpanel and history is None: for button in buttons: if self.is_button(button, 'Undo') or self.is_button( button, 'Revert'): history = ui.history = UndoHistory() break # Create the panel. self.control = panel(ui) # if self.control.isinstance(QtGui.QTabWidget): # self.control.setTabBar(myQTabBar()) # Suppress the title if this is a subpanel or if we think it should be # superceded by the title of an "outer" widget (eg. a dock widget). title = view.title if (is_subpanel or (isinstance(parent, QtGui.QMainWindow) and not isinstance(parent.parent(), QtGui.QDialog)) or isinstance(parent, QtGui.QTabWidget)): title = "" # ============ Monkey Patch =============== if isinstance(parent, QtGui.QTabWidget): bar = parent.tabBar() if not isinstance(bar, myQTabBar): parent.setTabBar(myQTabBar()) # ========================================= # Panels must be widgets as it is only the TraitsUI PyQt code that can # handle them being layouts as well. Therefore create a widget if the # panel is not a widget or if we need a title or buttons. if not isinstance(self.control, QtGui.QWidget) or title != "" or has_buttons: w = QtGui.QWidget() layout = QtGui.QVBoxLayout(w) layout.setContentsMargins(0, 0, 0, 0) # Handle any view title. if title != "": layout.addWidget(heading_text(None, text=view.title).control) if isinstance(self.control, QtGui.QWidget): layout.addWidget(self.control) elif isinstance(self.control, QtGui.QLayout): layout.addLayout(self.control) self.control = w # Add any buttons. if has_buttons: # Add the horizontal separator separator = QtGui.QFrame() separator.setFrameStyle(QtGui.QFrame.Sunken | QtGui.QFrame.HLine) separator.setFixedHeight(2) layout.addWidget(separator) # Add the special function buttons bbox = QtGui.QDialogButtonBox(QtCore.Qt.Horizontal) for button in buttons: role = QtGui.QDialogButtonBox.ActionRole if self.is_button(button, 'Undo'): self.undo = self.add_button(button, bbox, role, self._on_undo, False, 'Undo') self.redo = self.add_button(button, bbox, role, self._on_redo, False, 'Redo') history.on_trait_change(self._on_undoable, 'undoable', dispatch='ui') history.on_trait_change(self._on_redoable, 'redoable', dispatch='ui') elif self.is_button(button, 'Revert'): role = QtGui.QDialogButtonBox.ResetRole self.revert = self.add_button(button, bbox, role, self._on_revert, False) history.on_trait_change(self._on_revertable, 'undoable', dispatch='ui') elif self.is_button(button, 'Help'): role = QtGui.QDialogButtonBox.HelpRole self.add_button(button, bbox, role, self._on_help) elif not self.is_button(button, ''): self.add_button(button, bbox, role) layout.addWidget(bbox) # Ensure the control has a size hint reflecting the View specification. # Yes, this is a hack, but it's too late to repair this convoluted # control building process, so we do what we have to... self.control.sizeHint = _size_hint_wrapper(self.control.sizeHint, ui)
def __init__(self, ui, parent, is_subpanel): """Initialise the object. """ self.ui = ui history = ui.history view = ui.view # Reset any existing history listeners. if history is not None: history.on_trait_change(self._on_undoable, 'undoable', remove=True) history.on_trait_change(self._on_redoable, 'redoable', remove=True) history.on_trait_change(self._on_revertable, 'undoable', remove=True) # Determine if we need any buttons or an 'undo' history. buttons = [self.coerce_button(button) for button in view.buttons] nr_buttons = len(buttons) has_buttons = (not is_subpanel and (nr_buttons != 1 or not self.is_button(buttons[0], ''))) if nr_buttons == 0: if view.undo: self.check_button(buttons, UndoButton) if view.revert: self.check_button(buttons, RevertButton) if view.help: self.check_button(buttons, HelpButton) if not is_subpanel and history is None: for button in buttons: if self.is_button(button, 'Undo') or self.is_button(button, 'Revert'): history = ui.history = UndoHistory() break # Create the panel. self.control = panel(ui) # if self.control.isinstance(QtGui.QTabWidget): # self.control.setTabBar(myQTabBar()) # Suppress the title if this is a subpanel or if we think it should be # superceded by the title of an "outer" widget (eg. a dock widget). title = view.title if (is_subpanel or (isinstance(parent, QtGui.QMainWindow) and not isinstance(parent.parent(), QtGui.QDialog)) or isinstance(parent, QtGui.QTabWidget)): title = "" # ============ Monkey Patch =============== if isinstance(parent, QtGui.QTabWidget): bar = parent.tabBar() if not isinstance(bar, myQTabBar): parent.setTabBar(myQTabBar()) # p = parent # while p is not None: # try: # bar = p.tabBar() # except AttributeError: # bar = None # print p, bar # p = p.parent() # ========================================= # Panels must be widgets as it is only the TraitsUI PyQt code that can # handle them being layouts as well. Therefore create a widget if the # panel is not a widget or if we need a title or buttons. if not isinstance(self.control, QtGui.QWidget) or title != "" or has_buttons: w = QtGui.QWidget() layout = QtGui.QVBoxLayout(w) layout.setContentsMargins(0, 0, 0, 0) # Handle any view title. if title != "": layout.addWidget(heading_text(None, text=view.title).control) if isinstance(self.control, QtGui.QWidget): layout.addWidget(self.control) elif isinstance(self.control, QtGui.QLayout): layout.addLayout(self.control) self.control = w # Add any buttons. if has_buttons: # Add the horizontal separator separator = QtGui.QFrame() separator.setFrameStyle(QtGui.QFrame.Sunken | QtGui.QFrame.HLine) separator.setFixedHeight(2) layout.addWidget(separator) # Add the special function buttons bbox = QtGui.QDialogButtonBox(QtCore.Qt.Horizontal) for button in buttons: role = QtGui.QDialogButtonBox.ActionRole if self.is_button(button, 'Undo'): self.undo = self.add_button(button, bbox, role, self._on_undo, False, 'Undo') self.redo = self.add_button(button, bbox, role, self._on_redo, False, 'Redo') history.on_trait_change(self._on_undoable, 'undoable', dispatch='ui') history.on_trait_change(self._on_redoable, 'redoable', dispatch='ui') elif self.is_button(button, 'Revert'): role = QtGui.QDialogButtonBox.ResetRole self.revert = self.add_button(button, bbox, role, self._on_revert, False) history.on_trait_change(self._on_revertable, 'undoable', dispatch='ui') elif self.is_button(button, 'Help'): role = QtGui.QDialogButtonBox.HelpRole self.add_button(button, bbox, role, self._on_help) elif not self.is_button(button, ''): self.add_button(button, bbox, role) layout.addWidget(bbox) # Ensure the control has a size hint reflecting the View specification. # Yes, this is a hack, but it's too late to repair this convoluted # control building process, so we do what we have to... self.control.sizeHint = _size_hint_wrapper(self.control.sizeHint, ui)