def __init__(self, group, text, pos, fsize=18, padding=8, name='', **kwargs): """Radiobutton with a optional text label. group - the widget to which this button belongs. (must be None or another radiobutton) text - string to display pos - position to display the box fsize - Font size padding - space in pixels around the text name - string to indicate this object kwargs - bgcol, fgcol """ self.box_pos = pos self.image_pos = (pos[0]+1, pos[1]+1) self.name = name if not group: self._rb_group = [self] else: self._rb_group = group._rb_group + [self] for rb in self._rb_group: rb._rb_group = self._rb_group self._rb_selected = False box = pygame.Surface((18, 18)) box.fill(WHITE) rect = box.get_rect() lbl = Label(text, (pos[0] + 10 + rect.width, pos[1]), fsize=18, transparent=True, \ fgcol=WHITE, bold=True) lbl.display_sprite() pygame.draw.line(box, GREY30, (0, 0), (18, 0), 1) pygame.draw.line(box, GREY30, (0, 0), (0, 18), 1) pygame.draw.line(box, GREY30, (17, 0), (17, 17), 1) pygame.draw.line(box, GREY30, (1, 17), (17, 17), 1) self.box = box.convert() Widget.__init__(self, box, name=name) self.selected_image = utils.load_image(os.path.join(self.THEME['defaultpath'], 'radiobut_selected.png')) self.moveto(self.box_pos) self.connect_callback(self._cbf_on_select, MOUSEBUTTONUP)
def __init__(self, interactor, action=None, corner_radius=5, width=None, font="Arial", height=None, left=0, top=0, image=None, label="", bgcolor=(.5, .5, .5), fgcolor=(1,1,1), opacity=1, size=14, states = None, halign=LEFT_ALIGN, valign=CENTER_ALIGN, tooltip=None, tooltip_property=None): """ @kwargs: action: A callback function that will receive the current state ID when the button is clicked. width: if width is None, use the size of the label to determine width height: if height is None, use the size of the label to determine height left: Distance from the left of the window to place the button top: Distance from the top of the window to place the button image: Icon to place on top of the background label: Default label to use for all states (if no states are provided, creates a state using defaults) bgcolor: Default background color of the button (if states do not provide a bgcolor, this one is used) fgcolor: Default font color of the label (if states do not provide an fgcolor, this one is used) opacity: Default opacity of button & label (if states do not provide an opacity, this one is used) size: Default font size of the label (if states do not provide a font size, this one is used) halign: If the button states have multiple widths (different labels/images), this will align them horizontally as specified valign: If the button states have multiple heights (labels with newlines, images), this will align them vertically as specified """ self.width = width self.height = height self.left = left self.top = top self.radius = corner_radius self.action = action if halign not in (LEFT_ALIGN, RIGHT_ALIGN, CENTER_ALIGN): raise TypeError("halign must be one of LEFT_ALIGN, RIGHT_ALIGN, or CENTER_ALIGN") self.halign = halign if valign not in (TOP_ALIGN, BOTTOM_ALIGN, CENTER_ALIGN): raise TypeError("valign must be one of TOP_ALIGN, BOTTOM_ALIGN, or CENTER_ALIGN") self.valign = valign if image: self.image = load_image(image) else: self.image = None self.__placing__ = False text = states[0].label if states else label # Text widget will be placed over the button; clicks on it have to propogate down self.text_widget = Label(interactor, text, on_click = self.__advance__, size=size, font=font) self.label = label self.size = size self.opacity = opacity self.fgcolor = fgcolor self.bgcolor = bgcolor if states: self.states = states else: self.states = [ButtonState(label=label)] widget = vtk.vtkButtonWidget() widget.SetRepresentation(vtk.vtkTexturedButtonRepresentation2D()) super(Button, self).__init__(interactor, widget) if tooltip: if tooltip_property is not None: tooltip_property.SetVerticalJustificationToTop() self.tooltip_label = Label(interactor, tooltip, textproperty=tooltip_property) self.hover_handler = self.interactor.AddObserver("MouseMoveEvent", self.hover) self.hover_timer = None self.timer_handler = self.interactor.AddObserver("TimerEvent", self.still_hovering) self.update() self.subscribe( 'StateChangedEvent', self.clicked)
class Button(Widget): def __init__(self, interactor, action=None, corner_radius=5, width=None, font="Arial", height=None, left=0, top=0, image=None, label="", bgcolor=(.5, .5, .5), fgcolor=(1,1,1), opacity=1, size=14, states = None, halign=LEFT_ALIGN, valign=CENTER_ALIGN, tooltip=None, tooltip_property=None): """ @kwargs: action: A callback function that will receive the current state ID when the button is clicked. width: if width is None, use the size of the label to determine width height: if height is None, use the size of the label to determine height left: Distance from the left of the window to place the button top: Distance from the top of the window to place the button image: Icon to place on top of the background label: Default label to use for all states (if no states are provided, creates a state using defaults) bgcolor: Default background color of the button (if states do not provide a bgcolor, this one is used) fgcolor: Default font color of the label (if states do not provide an fgcolor, this one is used) opacity: Default opacity of button & label (if states do not provide an opacity, this one is used) size: Default font size of the label (if states do not provide a font size, this one is used) halign: If the button states have multiple widths (different labels/images), this will align them horizontally as specified valign: If the button states have multiple heights (labels with newlines, images), this will align them vertically as specified """ self.width = width self.height = height self.left = left self.top = top self.radius = corner_radius self.action = action if halign not in (LEFT_ALIGN, RIGHT_ALIGN, CENTER_ALIGN): raise TypeError("halign must be one of LEFT_ALIGN, RIGHT_ALIGN, or CENTER_ALIGN") self.halign = halign if valign not in (TOP_ALIGN, BOTTOM_ALIGN, CENTER_ALIGN): raise TypeError("valign must be one of TOP_ALIGN, BOTTOM_ALIGN, or CENTER_ALIGN") self.valign = valign if image: self.image = load_image(image) else: self.image = None self.__placing__ = False text = states[0].label if states else label # Text widget will be placed over the button; clicks on it have to propogate down self.text_widget = Label(interactor, text, on_click = self.__advance__, size=size, font=font) self.label = label self.size = size self.opacity = opacity self.fgcolor = fgcolor self.bgcolor = bgcolor if states: self.states = states else: self.states = [ButtonState(label=label)] widget = vtk.vtkButtonWidget() widget.SetRepresentation(vtk.vtkTexturedButtonRepresentation2D()) super(Button, self).__init__(interactor, widget) if tooltip: if tooltip_property is not None: tooltip_property.SetVerticalJustificationToTop() self.tooltip_label = Label(interactor, tooltip, textproperty=tooltip_property) self.hover_handler = self.interactor.AddObserver("MouseMoveEvent", self.hover) self.hover_timer = None self.timer_handler = self.interactor.AddObserver("TimerEvent", self.still_hovering) self.update() self.subscribe( 'StateChangedEvent', self.clicked) def hover(self, obj, event): if self.widget.GetEnabled() == 0: return x, y = self.interactor.GetEventPosition() if self.hover_timer is None and self.tooltip_label.showing() == False: if self.in_bounds(x, y): self.hover_timer = self.interactor.CreateOneShotTimer(300) if self.in_bounds(x, y) == False: if self.hover_timer is not None: self.interactor.DestroyTimer(self.hover_timer) self.hover_timer = None if self.tooltip_label.showing(): self.tooltip_label.hide() def still_hovering(self, obj, event): if self.hover_timer: self.tooltip_label.place() self.tooltip_label.show() self.hover_timer = None def get_text(self): return self.text_widget.get_text() def add_state(self, label=None, image=None, bgcolor=None, fgcolor=None, opacity=None): self.states.append(ButtonState(label=label, image=image, bgcolor=bgcolor, fgcolor=fgcolor, opacity=opacity)) def place(self): width, height = self.get_dimensions() x, y = self.get_position() bounds = (x, x + width, y - height, y, 0, 0) self.repr.SetPlaceFactor(1) self.repr.PlaceWidget(bounds) self.repr.Modified() if self.showing(): # This One Weird Hack will make your Buttons Go In the Right Place - Developers hate it! # Buttons weren't always getting properly placed (toolbars in toolbars being the canonical example) # This makes them show up correctly. Weird, but it works. h_state = self.repr.GetHighlightState() self.repr.Highlight((h_state + 1) % 3) self.repr.Highlight(h_state) text_width, text_height = self.text_widget.get_dimensions() swidth, sheight = self.interactor.GetRenderWindow().GetSize() self.text_widget.left = x + (width - text_width) / 2.0 self.text_widget.top = sheight - y + BUTTON_MARGIN self.text_widget.place() try: w, h = self.tooltip_label.get_dimensions() if x + 5 + w < swidth: self.tooltip_label.left = x + 5 else: self.tooltip_label.left = swidth - w - 5 self.tooltip_label.top = sheight - (y - height) self.tooltip_label.place() except AttributeError: pass def get_dimensions(self): image = self.repr.GetButtonTexture(self.repr.GetState()) width, height, _ = image.GetDimensions() return width, height def update(self): self.repr.SetNumberOfStates(len(self.states)) max_width = 0 max_height = 0 for index, state in enumerate(self.states): # Set up attributes with defaults if nothing is set label_text = state.label if state.label else self.label image = state.image if state.image else self.image if image: # Image supersedes label w, h, _ = image.GetDimensions() # Use a 3 px padding for now max_height = max(max_height, h) max_width = max(max_width, w) elif label_text: l_w, l_h = text_dimensions(label_text, self.text_widget.actor.GetTextProperty()) max_height = max(max_height, l_h) max_width = max(max_width, l_w) # Pad the text max_width += 2 * BUTTON_MARGIN max_height += 2 * BUTTON_MARGIN for index, state in enumerate(self.states): image = state.image if state.image else self.image bgcolor = state.bgcolor if state.bgcolor else self.bgcolor # Opacity not yet supported by this code #opacity = state.opacity if state.opacity else self.opacity # Something weird happens when images of drastically different sizes are passed in; # not hunting down that fix right now. if image is not None: width, height, _ = image.GetDimensions() else: width = self.width if self.width else int(max_width) height = self.height if self.height else int(max_height) # Optimization can be done here; can use the same image for everything with same bgcolor + h/w bg_image = rounded_rect(width, height, self.radius, bgcolor) if image is not None: image = pad_image(image, max_width, max_height) bg_image = combine_images(bg_image, image) # Should deal with opacity here-ish self.repr.SetButtonTexture(index, bg_image) def get_position(self): default_texture = self.repr.GetButtonTexture(0) dwidth, dheight, _ = default_texture.GetDimensions() width, height = self.get_dimensions() window = self.interactor.GetRenderWindow() size = window.GetSize() if self.halign == LEFT_ALIGN: left = self.left elif self.halign == CENTER_ALIGN: left = (self.left - (width - dwidth) / 2) elif self.halign == RIGHT_ALIGN: left = size[0] - self.left - width if dheight == height or self.valign == TOP_ALIGN: top = self.top elif self.valign == CENTER_ALIGN: top = (self.top - (height - dheight) / 2) elif self.valign == BOTTOM_ALIGN: top = size[1] - (self.top - (height - dheight)) return left, size[1] - top def get_state(self): return self.repr.GetState() def set_state(self, state): new_state = self.states[state] label = self.label if new_state.label is None else new_state.label self.text_widget.set_text(label) self.repr.SetState(state) self.place() def show(self): super(Button, self).show() self.text_widget.show() self.place() def detach(self): self.text_widget.detach() self.text_widget = None try: self.tooltip_label.detach() self.tooltip_label = None self.interactor.RemoveObserver(self.hover_handler) except: pass self.action = None super(Button, self).detach() def hide(self): super(Button, self).hide() try: self.tooltip_label.hide() except AttributeError: pass self.text_widget.hide() def in_bounds(self, x, y): w, h = self.get_dimensions() box_x, box_y = self.get_position() return x < box_x + w and x > box_x and y > box_y - h and y < box_y def __advance__(self, point): state = self.repr.GetState() self.set_state( (state + 1) % len(self.states) ) self.clicked(self.widget, "StateChangedEvent") def clicked(self, obj, event): state = self.get_state() button_state = self.states[state] self.text_widget.set_text( button_state.label if button_state.label else self.label ) self.text_widget.set_font_color( button_state.fgcolor if button_state.fgcolor else self.fgcolor ) self.place() if self.action: self.action(state) def copy(self, interactor, button_type=None, button_args=None, button_kwargs=None, skip_args=None): # In the future, we'll want to do some optimization with states and images here. b = Button(interactor, action=self.action, corner_radius=self.radius, width=self.width, height=self.height, left=self.left, top=self.top, image=self.image, label=self.label, bgcolor=self.bgcolor, fgcolor=self.fgcolor, opacity=self.opacity, size=self.size, states = self.states, halign=self.halign, valign=self.valign) state = self.get_state() if state != 0: b.set_state(state) b.action(state) return b
def __init__(self, interactor, action=None, corner_radius=5, width=None, font="Arial", height=None, left=0, top=0, image=None, label="", bgcolor=(.5, .5, .5), fgcolor=(1, 1, 1), opacity=1, size=14, states=None, halign=LEFT_ALIGN, valign=CENTER_ALIGN, tooltip=None, tooltip_property=None): """ @kwargs: action: A callback function that will receive the current state ID when the button is clicked. width: if width is None, use the size of the label to determine width height: if height is None, use the size of the label to determine height left: Distance from the left of the window to place the button top: Distance from the top of the window to place the button image: Icon to place on top of the background label: Default label to use for all states (if no states are provided, creates a state using defaults) bgcolor: Default background color of the button (if states do not provide a bgcolor, this one is used) fgcolor: Default font color of the label (if states do not provide an fgcolor, this one is used) opacity: Default opacity of button & label (if states do not provide an opacity, this one is used) size: Default font size of the label (if states do not provide a font size, this one is used) halign: If the button states have multiple widths (different labels/images), this will align them horizontally as specified valign: If the button states have multiple heights (labels with newlines, images), this will align them vertically as specified """ # noqa self.width = width self.height = height self.left = left self.top = top self.radius = corner_radius self.action = action if halign not in (LEFT_ALIGN, RIGHT_ALIGN, CENTER_ALIGN): raise TypeError( "halign must be one of LEFT_ALIGN, RIGHT_ALIGN, or CENTER_ALIGN" ) self.halign = halign if valign not in (TOP_ALIGN, BOTTOM_ALIGN, CENTER_ALIGN): raise TypeError( "valign must be one of TOP_ALIGN, BOTTOM_ALIGN, or CENTER_ALIGN" ) self.valign = valign if image: self.image = load_image(image) else: self.image = None self.__placing__ = False text = states[0].label if states else label # Text widget will be placed over the button; clicks on it have to # propogate down self.text_widget = Label(interactor, text, on_click=self.__advance__, size=size, font=font) self.label = label self.size = size self.opacity = opacity self.fgcolor = fgcolor self.bgcolor = bgcolor if states: self.states = states else: self.states = [ButtonState(label=label)] widget = vtk.vtkButtonWidget() widget.SetRepresentation(vtk.vtkTexturedButtonRepresentation2D()) super(Button, self).__init__(interactor, widget) if tooltip: if tooltip_property is not None: tooltip_property.SetVerticalJustificationToTop() self.tooltip_label = Label(interactor, tooltip, textproperty=tooltip_property) self.hover_handler = self.interactor.AddObserver( "MouseMoveEvent", self.hover) self.hover_timer = None self.timer_handler = self.interactor.AddObserver( "TimerEvent", self.still_hovering) self.update() self.subscribe('StateChangedEvent', self.clicked)
class Button(Widget): def __init__(self, interactor, action=None, corner_radius=5, width=None, font="Arial", height=None, left=0, top=0, image=None, label="", bgcolor=(.5, .5, .5), fgcolor=(1, 1, 1), opacity=1, size=14, states=None, halign=LEFT_ALIGN, valign=CENTER_ALIGN, tooltip=None, tooltip_property=None): """ @kwargs: action: A callback function that will receive the current state ID when the button is clicked. width: if width is None, use the size of the label to determine width height: if height is None, use the size of the label to determine height left: Distance from the left of the window to place the button top: Distance from the top of the window to place the button image: Icon to place on top of the background label: Default label to use for all states (if no states are provided, creates a state using defaults) bgcolor: Default background color of the button (if states do not provide a bgcolor, this one is used) fgcolor: Default font color of the label (if states do not provide an fgcolor, this one is used) opacity: Default opacity of button & label (if states do not provide an opacity, this one is used) size: Default font size of the label (if states do not provide a font size, this one is used) halign: If the button states have multiple widths (different labels/images), this will align them horizontally as specified valign: If the button states have multiple heights (labels with newlines, images), this will align them vertically as specified """ # noqa self.width = width self.height = height self.left = left self.top = top self.radius = corner_radius self.action = action if halign not in (LEFT_ALIGN, RIGHT_ALIGN, CENTER_ALIGN): raise TypeError( "halign must be one of LEFT_ALIGN, RIGHT_ALIGN, or CENTER_ALIGN" ) self.halign = halign if valign not in (TOP_ALIGN, BOTTOM_ALIGN, CENTER_ALIGN): raise TypeError( "valign must be one of TOP_ALIGN, BOTTOM_ALIGN, or CENTER_ALIGN" ) self.valign = valign if image: self.image = load_image(image) else: self.image = None self.__placing__ = False text = states[0].label if states else label # Text widget will be placed over the button; clicks on it have to # propogate down self.text_widget = Label(interactor, text, on_click=self.__advance__, size=size, font=font) self.label = label self.size = size self.opacity = opacity self.fgcolor = fgcolor self.bgcolor = bgcolor if states: self.states = states else: self.states = [ButtonState(label=label)] widget = vtk.vtkButtonWidget() widget.SetRepresentation(vtk.vtkTexturedButtonRepresentation2D()) super(Button, self).__init__(interactor, widget) if tooltip: if tooltip_property is not None: tooltip_property.SetVerticalJustificationToTop() self.tooltip_label = Label(interactor, tooltip, textproperty=tooltip_property) self.hover_handler = self.interactor.AddObserver( "MouseMoveEvent", self.hover) self.hover_timer = None self.timer_handler = self.interactor.AddObserver( "TimerEvent", self.still_hovering) self.update() self.subscribe('StateChangedEvent', self.clicked) def hover(self, obj, event): if self.widget.GetEnabled() == 0: return x, y = self.interactor.GetEventPosition() if self.hover_timer is None and self.tooltip_label.showing() is False: if self.in_bounds(x, y): self.hover_timer = self.interactor.CreateOneShotTimer(300) if self.in_bounds(x, y) is False: if self.hover_timer is not None: self.interactor.DestroyTimer(self.hover_timer) self.hover_timer = None if self.tooltip_label.showing(): self.tooltip_label.hide() def still_hovering(self, obj, event): if self.hover_timer: self.tooltip_label.place() self.tooltip_label.show() self.hover_timer = None def get_text(self): return self.text_widget.get_text() def add_state(self, label=None, image=None, bgcolor=None, fgcolor=None, opacity=None): self.states.append( ButtonState(label=label, image=image, bgcolor=bgcolor, fgcolor=fgcolor, opacity=opacity)) def place(self): width, height = self.get_dimensions() x, y = self.get_position() bounds = (x, x + width, y - height, y, 0, 0) self.repr.SetPlaceFactor(1) self.repr.PlaceWidget(bounds) self.repr.Modified() if self.showing(): # This One Weird Hack will make your Buttons Go In the Right Place - Developers hate it! # Buttons weren't always getting properly placed (toolbars in toolbars being the canonical example) # This makes them show up correctly. Weird, but it works. h_state = self.repr.GetHighlightState() self.repr.Highlight((h_state + 1) % 3) self.repr.Highlight(h_state) else: # Can't properly place if not showing, so let's save some cycles. return text_width, text_height = self.text_widget.get_dimensions() swidth, sheight = self.interactor.GetRenderWindow().GetSize() self.text_widget.left = x + (width - text_width) / 2.0 self.text_widget.top = sheight - y + BUTTON_MARGIN self.text_widget.place() try: w, h = self.tooltip_label.get_dimensions() if x + 5 + w < swidth: self.tooltip_label.left = x + 5 else: self.tooltip_label.left = swidth - w - 5 self.tooltip_label.top = sheight - (y - height) self.tooltip_label.place() except AttributeError: pass def get_dimensions(self): image = self.repr.GetButtonTexture(self.repr.GetState()) width, height, _ = image.GetDimensions() return width, height def update(self): self.repr.SetNumberOfStates(len(self.states)) dpi = self.interactor.GetRenderWindow().GetDPI() max_width = 0 max_height = 0 for index, state in enumerate(self.states): # Set up attributes with defaults if nothing is set label_text = state.label if state.label else self.label image = state.image if state.image else self.image if image: # Image supersedes label w, h, _ = image.GetDimensions() # Use a 3 px padding for now max_height = max(max_height, h) max_width = max(max_width, w) elif label_text: l_w, l_h = text_dimensions( label_text, self.text_widget.actor.GetTextProperty(), dpi) max_height = max(max_height, l_h) max_width = max(max_width, l_w) # Pad the text max_width += 2 * BUTTON_MARGIN max_height += 2 * BUTTON_MARGIN for index, state in enumerate(self.states): image = state.image if state.image else self.image bgcolor = state.bgcolor if state.bgcolor else self.bgcolor # Opacity not yet supported by this code # opacity = state.opacity if state.opacity else self.opacity # Something weird happens when images of drastically different sizes are passed in; # not hunting down that fix right now. if image is not None: width, height, _ = image.GetDimensions() else: width = self.width if self.width else int(max_width) height = self.height if self.height else int(max_height) # Optimization can be done here; can use the same image for # everything with same bgcolor + h/w bg_image = rounded_rect(width, height, self.radius, bgcolor) if image is not None: image = pad_image(image, max_width, max_height) bg_image = combine_images(bg_image, image) # Should deal with opacity here-ish self.repr.SetButtonTexture(index, bg_image) def get_position(self): default_texture = self.repr.GetButtonTexture(0) dwidth, dheight, _ = default_texture.GetDimensions() width, height = self.get_dimensions() window = self.interactor.GetRenderWindow() size = window.GetSize() if self.halign == LEFT_ALIGN: left = self.left elif self.halign == CENTER_ALIGN: left = (self.left - (width - dwidth) / 2) elif self.halign == RIGHT_ALIGN: left = size[0] - self.left - width if dheight == height or self.valign == TOP_ALIGN: top = self.top elif self.valign == CENTER_ALIGN: top = (self.top - (height - dheight) / 2) elif self.valign == BOTTOM_ALIGN: top = size[1] - (self.top - (height - dheight)) return left, size[1] - top def get_state(self): return self.repr.GetState() def set_state(self, state): new_state = self.states[state] label = self.label if new_state.label is None else new_state.label self.text_widget.set_text(label) self.repr.SetState(state) self.place() def show(self): super(Button, self).show() self.text_widget.show() self.place() def detach(self): self.text_widget.detach() self.text_widget = None try: self.tooltip_label.detach() self.tooltip_label = None self.interactor.RemoveObserver(self.hover_handler) except: pass self.action = None super(Button, self).detach() def hide(self): super(Button, self).hide() try: self.tooltip_label.hide() except AttributeError: pass self.text_widget.hide() def in_bounds(self, x, y): w, h = self.get_dimensions() box_x, box_y = self.get_position() return x < box_x + w and x > box_x and y > box_y - h and y < box_y def __advance__(self, point): state = self.repr.GetState() self.set_state((state + 1) % len(self.states)) self.clicked(self.widget, "StateChangedEvent") def clicked(self, obj, event): state = self.get_state() button_state = self.states[state] self.text_widget.set_text( button_state.label if button_state.label else self.label) self.text_widget.set_font_color( button_state.fgcolor if button_state.fgcolor else self.fgcolor) self.place() if self.action: self.action(state) def copy(self, interactor, button_type=None, button_args=None, button_kwargs=None, skip_args=None): # In the future, we'll want to do some optimization with states and # images here. b = Button(interactor, action=self.action, corner_radius=self.radius, width=self.width, height=self.height, left=self.left, top=self.top, image=self.image, label=self.label, bgcolor=self.bgcolor, fgcolor=self.fgcolor, opacity=self.opacity, size=self.size, states=self.states, halign=self.halign, valign=self.valign) state = self.get_state() if state != 0: b.set_state(state) b.action(state) return b
import sys from PySide2.QtGui import QIcon, QStandardItem, QStandardItemModel from PySide2.QtCore import QObject, QRunnable, Qt, QThread, QThreadPool, Signal, Slot class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent=parent) self.setupUi(self) @Slot(str) def cs(self): print("x") self.lineEdit.setPlaceholderText("gnuh") if __name__ == "__main__": app = QApplication(sys.argv) w = MainWindow() options_model = QStandardItemModel(w.listView) individual_option = QStandardItem("butts") options_model.appendRow(individual_option) w.pushButton.clicked.connect(w.cs) w.pushButton.clicked.connect(call_conan) w.verticalLayout.addWidget(QPushButton("wee!")) w.verticalLayout.addWidget(Label("An Label")) w.show() sys.exit(app.exec_())
def __init__(self, name): super().__init__() print('loading subcircuit {}...'.format(name)) if not os.path.isdir(os.path.join('subcircuits', name)): raise ValueError('subcircuit {} does not exist'.format(name)) if not os.path.isfile(os.path.join('subcircuits', name, '{}.circuit.txt'.format(name))): raise ValueError('missing .circuit.txt file for subcircuit {}'.format(name)) cols = GridDimension(False) rows = GridDimension(True) self._name = name self._pins = Pins() self._interfaces = [] self._net_insns = [] self._net_ties = [] self._instances = [] self._routers = [] self._shunters = [] self._outlines = [] self._labels = [] instance_names = set() forwarded_pins = [] with open(os.path.join('subcircuits', name, '{}.circuit.txt'.format(name)), 'r') as f: for line in f.read().split('\n'): line = line.split('#', maxsplit=1)[0].strip() if not line: continue args = line.split() if args[0] == 'columns': cols.configure(*args[1:]) continue if args[0] == 'rows': rows.configure(*args[1:]) continue if args[0] in ('in', 'out'): coord = (cols.convert(args[3]), rows.convert(args[4])) self._pins.add(args[1], args[0], args[2], (0, 0), coord, 0.0) name = '.{}'.format(args[1]) self._net_insns.append((name, args[2], (0, 0), coord, 0.0, args[0])) continue if args[0] in ('fwd_in', 'fwd_out'): forwarded_pins.append((args[0][4:], args[1])) continue if args[0] in ('prim', 'subc'): coord = (cols.convert(args[4]), rows.convert(args[5])) rotation = float(args[3]) / 180 * math.pi instance_type = args[1] instance_name = args[2] if instance_name in instance_names: raise ValueError('duplicate instance name {}'.format(instance_name)) instance_names.add(instance_name) if args[0] == 'prim' and instance_type == 'tie': master = args[-1].split('=', maxsplit=1)[1] for arg in args[6:-1]: slave = arg.split('=', maxsplit=1)[1] self._net_ties.append(('.' + master, '.' + slave)) instance = Instance( args[0] == 'prim', instance_type, instance_name, coord, rotation, *args[6:] ) for pin, net in instance.get_pinmap(): if pin.is_output(): mode = 'driver' if args[0] == 'prim' else 'in' else: mode = 'user' if args[0] == 'prim' else 'out' self._net_insns.append(( net, pin.get_layer(), pin.get_coord(), transrot(pin.get_translate(), coord, rotation), pin.get_rotate() + rotation, mode )) self._instances.append(instance) for direction, vhd_type, iface in instance.get_data().get_interfaces(): self._interfaces.append((direction, vhd_type, '{}_{}'.format(instance_name, iface))) continue if args[0] == 'route': self._routers.append((cols.convert(args[1]), ['.{}'.format(x) for x in args[2:]])) continue if args[0] == 'shunt': coord1 = (cols.convert(args[1]), rows.convert(args[2])) net1 = '.{}'.format(args[3]) coord2 = (cols.convert(args[4]), rows.convert(args[5])) net2 = '.{}'.format(args[6]) layer = args[7] self._shunters.append((coord1, coord2, layer)) self._net_insns.append((net1, layer, (0, 0), coord1, 0, 'user')) self._net_insns.append((net2, layer, (0, 0), coord2, 0, 'user')) continue if args[0] in 'outline': self._outlines.append(( cols.convert(args[1]), rows.convert(args[2]), cols.convert(args[3]), rows.convert(args[4]), from_mm(args[5]), # expansion from_mm(args[6]), # corner radius args[7] )) continue if args[0] == 'text': text = args[1].replace('~', ' ') coord = (cols.convert(args[3]) + from_mm(args[5]), rows.convert(args[4]) + from_mm(args[6])) rotation = float(args[2]) / 180 * math.pi scale = float(args[7]) if len(args) > 7 else 1.0 halign = float(args[8]) if len(args) > 8 else 0.5 valign = float(args[9]) if len(args) > 9 else None self._labels.append(Label(text, coord, rotation, scale, halign, valign)) continue print('warning: unknown subcircuit construct: {}'.format(line)) forwarded_pin_nets = set() for direction, name in forwarded_pins: insns = [] for insn in self._net_insns: if insn[0] == '.' + name: insns.append(insn) if not insns: raise ValueError('cannot forward pins for nonexistant net {}'.format(name)) if len(insns) != 1: raise ValueError('multiple pins exist for forwarded pin {}; this is not supported'.format(name)) net, layer, coord, translate, rotate, mode = insns[0] self._pins.add(name, direction, layer, coord, translate, rotate) self._net_insns.append((net, layer, coord, translate, rotate, direction)) forwarded_pin_nets.add(net) print('doing basic DRC for subcircuit {}...'.format(self._name)) netlist = Netlist() for net, layer, coord, translate, rotate, mode in self._net_insns: netlist.add(net, layer, transrot(coord, translate, rotate), mode) good = netlist.check_subcircuit() unrouted = set(map(lambda x: x.get_name(), netlist.iter_logical())) routed = set() for x, nets in self._routers: ranges = [] for net in nets: if net in routed: print('net {} is routed multiple times'.format(net)) good = False elif net not in unrouted: print('net {} cannot be routed because it does not exist'.format(net)) good = False routed.add(net) unrouted.remove(net) y_min = None y_max = None for _, (_, y), _ in netlist.get_logical(net).iter_points(): if y_min is None or y < y_min: y_min = y if y_max is None or y > y_max: y_max = y assert y_min is not None assert y_max is not None ranges.append((y_min, y_max, net)) ranges.sort() for i in range(len(ranges) - 1): if ranges[i+1][0] - from_mm(0.5) < ranges[i][1]: print('nets {} and {} overlap in routing column;'.format(ranges[i][2], ranges[i+1][2])) print(' {} goes down to Y{} and {} up to Y{} at X{}'.format( ranges[i+1][2], to_mm(ranges[i+1][0]), ranges[i][2], to_mm(ranges[i][1]), to_mm(x))) good = False for net in forwarded_pin_nets: if net in routed: print('net {} is routed multiple times'.format(net)) good = False elif net not in unrouted: print('net {} cannot be routed because it does not exist'.format(net)) good = False routed.add(net) unrouted.remove(net) for net in unrouted: print('net {} is not routed'.format(net)) good = False if not good: raise ValueError('basic DRC failed for subcircuit {}'.format(self._name)) print('finished loading subcircuit {}, basic DRC passed'.format(self._name)) # Write VHDL for the netlist. with open(os.path.join('subcircuits', self._name, '{}.gen.vhd'.format(self._name)), 'w') as f: f.write('library ieee;\nuse ieee.std_logic_1164.all;\n\nentity {} is\n port (\n'.format(self._name)) pin_directions = {} for pin in self._pins: direction = pin.get_direction() pin = pin.get_name().split('~')[0].split('*')[0] if pin in pin_directions: if direction == 'out': pin_directions[pin] = 'out' else: pin_directions[pin] = direction first = True nets = set() for pin in self._pins: pin = pin.get_name().split('~')[0].split('*')[0] direction = pin_directions[pin] if pin in nets: continue nets.add(pin) if first: first = False else: f.write(';\n') f.write(' {} : {} std_logic'.format(pin, direction)) for direction, vhd_type, iface_name in self._interfaces: if first: first = False else: f.write(';\n') f.write(' if_{} : {} {}'.format(iface_name, direction, vhd_type)) f.write('\n );\nend entity;\n\narchitecture model of {} is\n'.format(self._name)) for net, *_ in self._net_insns: if not net.startswith('.'): continue net = net[1:].split('~')[0].split('*')[0] if net in nets: continue f.write(' signal {} : std_logic;\n'.format(net)) nets.add(net) f.write('begin\n\n') for instance in self._instances: name = instance.get_name().replace('*', '').replace('~', '') f.write(' {}_inst: entity work.{}\n port map (\n'.format(name, instance.get_data().get_name())) pins = set() first = True for pin, net in instance.get_pinmap(): pin = pin.get_name().split('~')[0].split('*')[0] if pin in pins: continue pins.add(pin) net = net[1:].split('~')[0].split('*')[0] if first: first = False else: f.write(',\n') f.write(' {} => {}'.format(pin, net)) for _, _, iface_name in instance.get_data().get_interfaces(): if first: first = False else: f.write(',\n') f.write(' if_{} => if_{}_{}'.format(iface_name, name, iface_name)) f.write('\n );\n\n') f.write('end architecture;\n')