def layout(self): top_height = self.TOP_HEIGHT bottom_height = self.BOTTOM_HEIGHT # add a title label at the top if ((self.scene()) and (not self.title_proxy)): title_view = view.NameLabel(self.unit) self.title_proxy = self.scene().addWidget(title_view) self.title_proxy.setParentItem(self) r = self.boundingRect() r.adjust(1, 1, -1, -1) if (self.title_proxy): title_view = self.title_proxy.widget() title_view.setFixedWidth(r.width() - (2 * top_height)) title_height = title_view.geometry().height() self.title_proxy.setPos( QPointF(top_height, (top_height - title_height) / 2.0)) # make a button to delete the unit if (self.allow_delete): if ((self.scene()) and (not self._delete_button)): self._delete_button = DeleteButton(self) self._delete_button.clicked.connect(self.on_delete) if (self._delete_button): self._delete_button.setRect( QRectF(r.right() - top_height, r.top(), top_height, top_height)) elif (self._delete_button): self._delete_button.destroy() self._delete_button = None # make a button to add to the unit if (self.allow_add): if ((self.scene()) and (not self._add_button)): self._add_button = AddButton(self) self._add_button.clicked.connect(self.on_add) if (self._add_button): self._add_button.setRect( QRectF(r.left(), r.bottom() - bottom_height, bottom_height, bottom_height)) elif (self._add_button): self._add_button.destroy() self._add_button = None # make a button to drag the unit if ((self.scene()) and (not self._drag_button)): self._drag_button = DragButton(self, self.unit) if (self._drag_button): self._drag_button.setRect( QRectF(r.left(), r.top(), top_height, top_height)) # make a button to resize the unit if ((self.allow_resize_width) or (self.allow_resize_height)): if ((self.scene()) and (not self._resize_button)): self._resize_button = ResizeButton( self, target=self.unit, horizontal=self.allow_resize_width, vertical=self.allow_resize_height) self._resize_button.resize.connect(self.on_resize) if (self._resize_button): self._resize_button.setRect( QRectF(r.right() - bottom_height, r.bottom() - bottom_height, bottom_height, bottom_height)) elif (self._resize_button): self._resize_button.resize.disconnect(self.on_resize) self._resize_button.destroy() self._resize_button = None # position the content, if any m = self.MARGIN content_pos = QPointF(m, m + top_height) content_height = 0.0 if (self._content): self._content.setPos(content_pos) content_height = self._content.boundingRect().height() # position inputs and outputs left and right of the content io_rect = QRectF(0.0, content_pos.y(), r.width(), content_height) if (self._input_layout): self._input_layout.setRect(io_rect) if (self._output_layout): self._output_layout.setRect(io_rect)
def layout(self): top_height = self.TOP_HEIGHT bottom_height = self.BOTTOM_HEIGHT # add a title label at the top if ((self.scene()) and (not self.title_proxy)): title_view = view.NameLabel(self.unit) self.title_proxy = self.scene().addWidget(title_view) self.title_proxy.setParentItem(self) r = self.boundingRect() r.adjust(1, 1, -1, -1) if (self.title_proxy): title_view = self.title_proxy.widget() title_view.setFixedWidth(r.width() - (2 * top_height)) title_height = title_view.geometry().height() self.title_proxy.setPos( QPointF(top_height, (top_height - title_height) / 2.0)) # make a button to delete the unit if (self.allow_delete): if ((self.scene()) and (not self._delete_button)): self._delete_button = DeleteButton(self) self._delete_button.clicked.connect(self.on_delete) if (self._delete_button): self._delete_button.setRect( QRectF(r.right() - top_height, r.top(), top_height, top_height)) elif (self._delete_button): self._delete_button.destroy() self._delete_button = None # make a button to add to the unit if (self.allow_add): if ((self.scene()) and (not self._add_button)): self._add_button = AddButton(self) self._add_button.clicked.connect(self.on_add) if (self._add_button): self._add_button.setRect( QRectF(r.left(), r.bottom() - bottom_height, bottom_height, bottom_height)) elif (self._add_button): self._add_button.destroy() self._add_button = None # make a button to drag the unit if ((self.scene()) and (not self._drag_button)): self._drag_button = DragButton(self, self.unit) if (self._drag_button): self._drag_button.setRect( QRectF(r.left(), r.top(), top_height, top_height)) # make a button to resize the unit if ((self.allow_resize_width) or (self.allow_resize_height)): if ((self.scene()) and (not self._resize_button)): self._resize_button = ResizeButton(self, target=self.unit, horizontal=self.allow_resize_width, vertical=self.allow_resize_height) self._resize_button.resize.connect(self.on_resize) if (self._resize_button): self._resize_button.setRect( QRectF(r.right() - bottom_height, r.bottom() - bottom_height, bottom_height, bottom_height)) elif (self._resize_button): self._resize_button.resize.disconnect(self.on_resize) self._resize_button.destroy() self._resize_button = None # position the content, if any m = self.MARGIN content_pos = QPointF(m, m + top_height) content_height = 0.0 if (self._content): self._content.setPos(content_pos) content_height = self._content.boundingRect().height() # position inputs and outputs left and right of the content io_rect = QRectF(0.0, content_pos.y(), r.width(), content_height) if (self._input_layout): self._input_layout.setRect(io_rect) if (self._output_layout): self._output_layout.setRect(io_rect)
class UnitView(view.Selectable, view.ModelView): # define a mapping from unit classes to specific view classes _unit_class_to_view_class = dict() # the margin to leave around the content MARGIN = 10.0 # the height of the bar at the top, containing the title and buttons TOP_HEIGHT = 24.0 # the height of the bar at the bottom, containing the add and resize buttons BOTTOM_HEIGHT = 24.0 def __init__(self, *args, **kwargs): view.ModelView.__init__(self, *args, **kwargs) view.Selectable.__init__(self) self.title_proxy = None self._size = QSizeF(60.0, 40.0) self._content = None self._input_layout = None self._output_layout = None self.allow_delete = True self._delete_button = None self._drag_button = None self.allow_resize_width = False self.allow_resize_height = False self._resize_button = None self.allow_add = False self._add_button = None # editing the title may change the width of the unit self.unit.name_changed.connect(self.on_name_changed) # show a normal cursor to override the workspace cursor self.setCursor(Qt.ArrowCursor) def destroy(self): if (self._resize_button): self._resize_button.resize.disconnect(self.on_resize) self.unit.name_changed.disconnect(self.on_name_changed) # removing the content will change the unit view's geometry briefly self.prepareGeometryChange() view.ModelView.destroy(self) @property def unit(self): return (self._model) # return whether the unit view is being moved or resized @property def moving(self): return (((self._drag_button) and (self._drag_button.dragging)) or ((self._resize_button) and (self._resize_button.dragging))) # register a class for use as a unit view @classmethod def register_unit_view(cls, unit_class, view_class): cls._unit_class_to_view_class[unit_class] = view_class # get an appropriate view for a unit @classmethod def view_for_unit(cls, unit): unit_class = unit.__class__ if (unit_class in cls._unit_class_to_view_class): view_class = cls._unit_class_to_view_class[unit_class] return (view_class(unit)) return (UnitView(unit)) # handle the user wanting to remove the unit def on_delete(self): document_view = self.parentItemWithAttribute('document') if (document_view): document = document_view.document inputs = () outputs = () if (self._input_layout is not None): inputs = self._input_layout.items if (self._output_layout is not None): outputs = self._output_layout.items document.remove_unit(self.unit, inputs=inputs, outputs=outputs) # handle the user wanting to add to the unit (this will have different # behaviors depending on the type of unit) def on_add(self): pass # get the size of the content (override for independent sizing) def content_size(self): return (self._content.boundingRect().size()) # manage the rect to keep it centered on the content size def rect(self): r = view.ModelView.rect(self) if (self._content): m = self.MARGIN content_size = self.content_size() w = content_size.width() + (m * 2) h = content_size.height() + (m * 2) h += self.TOP_HEIGHT if ((self.allow_resize_width) or (self.allow_resize_height) or (self.allow_add)): h += self.BOTTOM_HEIGHT r.setWidth(w) r.setHeight(h) # make sure there's enough space for the title top_width = (2 * self.TOP_HEIGHT) if (self.title_proxy): title_view = self.title_proxy.widget() tr = title_view.minimumSizeHint() top_width += tr.width() r.setWidth(max(r.width(), top_width)) return (r) def setRect(self, rect): posChanged = ((rect.x() != self.pos().x()) or (rect.y() != self.pos().y())) if (posChanged): self.prepareGeometryChange() self.setPos(rect.x(), rect.y()) def on_name_changed(self): self.prepareGeometryChange() self.layout() def on_resize(self, event, width, height): delta_width = width - self.unit.width delta_height = height - self.unit.height if (event.modifiers() == Qt.ShiftModifier): delta_x = delta_width / 2.0 delta_y = delta_height / 2.0 workspace_view = self.parentItemWithAttribute('units') if (workspace_view is not None): for other_unit in workspace_view.units: if ((other_unit is not self.unit) and (not isinstance(other_unit, unit.GroupUnit))): if (other_unit.x < self.unit.x): other_unit.x -= delta_x elif (other_unit.x > self.unit.x): other_unit.x += delta_x if (other_unit.y < self.unit.y): other_unit.y -= delta_y elif (other_unit.y > self.unit.y): other_unit.y += delta_y def layout(self): top_height = self.TOP_HEIGHT bottom_height = self.BOTTOM_HEIGHT # add a title label at the top if ((self.scene()) and (not self.title_proxy)): title_view = view.NameLabel(self.unit) self.title_proxy = self.scene().addWidget(title_view) self.title_proxy.setParentItem(self) r = self.boundingRect() r.adjust(1, 1, -1, -1) if (self.title_proxy): title_view = self.title_proxy.widget() title_view.setFixedWidth(r.width() - (2 * top_height)) title_height = title_view.geometry().height() self.title_proxy.setPos( QPointF(top_height, (top_height - title_height) / 2.0)) # make a button to delete the unit if (self.allow_delete): if ((self.scene()) and (not self._delete_button)): self._delete_button = DeleteButton(self) self._delete_button.clicked.connect(self.on_delete) if (self._delete_button): self._delete_button.setRect( QRectF(r.right() - top_height, r.top(), top_height, top_height)) elif (self._delete_button): self._delete_button.destroy() self._delete_button = None # make a button to add to the unit if (self.allow_add): if ((self.scene()) and (not self._add_button)): self._add_button = AddButton(self) self._add_button.clicked.connect(self.on_add) if (self._add_button): self._add_button.setRect( QRectF(r.left(), r.bottom() - bottom_height, bottom_height, bottom_height)) elif (self._add_button): self._add_button.destroy() self._add_button = None # make a button to drag the unit if ((self.scene()) and (not self._drag_button)): self._drag_button = DragButton(self, self.unit) if (self._drag_button): self._drag_button.setRect( QRectF(r.left(), r.top(), top_height, top_height)) # make a button to resize the unit if ((self.allow_resize_width) or (self.allow_resize_height)): if ((self.scene()) and (not self._resize_button)): self._resize_button = ResizeButton( self, target=self.unit, horizontal=self.allow_resize_width, vertical=self.allow_resize_height) self._resize_button.resize.connect(self.on_resize) if (self._resize_button): self._resize_button.setRect( QRectF(r.right() - bottom_height, r.bottom() - bottom_height, bottom_height, bottom_height)) elif (self._resize_button): self._resize_button.resize.disconnect(self.on_resize) self._resize_button.destroy() self._resize_button = None # position the content, if any m = self.MARGIN content_pos = QPointF(m, m + top_height) content_height = 0.0 if (self._content): self._content.setPos(content_pos) content_height = self._content.boundingRect().height() # position inputs and outputs left and right of the content io_rect = QRectF(0.0, content_pos.y(), r.width(), content_height) if (self._input_layout): self._input_layout.setRect(io_rect) if (self._output_layout): self._output_layout.setRect(io_rect) # draw a box enclosing the content and title def _paint(self, qp): pen = self.pen() pen.setWidth(2.0) qp.setPen(pen) if (self.unit.selected): qp.setBrush(self.brush(0.30)) elif (self.unit.hue is not None): color = QColor() color.setHsvF(self.unit.hue, 1.0, 1.0, 0.30) qp.setBrush(QBrush(color)) else: qp.setBrush(self.brush(0.15)) r = self.boundingRect() r.adjust(1, 1, -1, -1) qp.drawRoundedRect(r, 4.0, 4.0)
class UnitView(view.Selectable, view.ModelView): # define a mapping from unit classes to specific view classes _unit_class_to_view_class = dict() # the margin to leave around the content MARGIN = 10.0 # the height of the bar at the top, containing the title and buttons TOP_HEIGHT = 24.0 # the height of the bar at the bottom, containing the add and resize buttons BOTTOM_HEIGHT = 24.0 def __init__(self, *args, **kwargs): view.ModelView.__init__(self, *args, **kwargs) view.Selectable.__init__(self) self.title_proxy = None self._size = QSizeF(60.0, 40.0) self._content = None self._input_layout = None self._output_layout = None self.allow_delete = True self._delete_button = None self._drag_button = None self.allow_resize_width = False self.allow_resize_height = False self._resize_button = None self.allow_add = False self._add_button = None # editing the title may change the width of the unit self.unit.name_changed.connect(self.on_name_changed) # show a normal cursor to override the workspace cursor self.setCursor(Qt.ArrowCursor) def destroy(self): if (self._resize_button): self._resize_button.resize.disconnect(self.on_resize) self.unit.name_changed.disconnect(self.on_name_changed) # removing the content will change the unit view's geometry briefly self.prepareGeometryChange() view.ModelView.destroy(self) @property def unit(self): return(self._model) # return whether the unit view is being moved or resized @property def moving(self): return(((self._drag_button) and (self._drag_button.dragging)) or ((self._resize_button) and (self._resize_button.dragging))) # register a class for use as a unit view @classmethod def register_unit_view(cls, unit_class, view_class): cls._unit_class_to_view_class[unit_class] = view_class # get an appropriate view for a unit @classmethod def view_for_unit(cls, unit): unit_class = unit.__class__ if (unit_class in cls._unit_class_to_view_class): view_class = cls._unit_class_to_view_class[unit_class] return(view_class(unit)) return(UnitView(unit)) # handle the user wanting to remove the unit def on_delete(self): document_view = self.parentItemWithAttribute('document') if (document_view): document = document_view.document inputs = () outputs = () if (self._input_layout is not None): inputs = self._input_layout.items if (self._output_layout is not None): outputs = self._output_layout.items document.remove_unit(self.unit, inputs=inputs, outputs=outputs) # handle the user wanting to add to the unit (this will have different # behaviors depending on the type of unit) def on_add(self): pass # get the size of the content (override for independent sizing) def content_size(self): return(self._content.boundingRect().size()) # manage the rect to keep it centered on the content size def rect(self): r = view.ModelView.rect(self) if (self._content): m = self.MARGIN content_size = self.content_size() w = content_size.width() + (m * 2) h = content_size.height() + (m * 2) h += self.TOP_HEIGHT if ((self.allow_resize_width) or (self.allow_resize_height) or (self.allow_add)): h += self.BOTTOM_HEIGHT r.setWidth(w) r.setHeight(h) # make sure there's enough space for the title top_width = (2 * self.TOP_HEIGHT) if (self.title_proxy): title_view = self.title_proxy.widget() tr = title_view.minimumSizeHint() top_width += tr.width() r.setWidth(max(r.width(), top_width)) return(r) def setRect(self, rect): posChanged = ((rect.x() != self.pos().x()) or (rect.y() != self.pos().y())) if (posChanged): self.prepareGeometryChange() self.setPos(rect.x(), rect.y()) def on_name_changed(self): self.prepareGeometryChange() self.layout() def on_resize(self, event, width, height): delta_width = width - self.unit.width delta_height = height - self.unit.height if (event.modifiers() == Qt.ShiftModifier): delta_x = delta_width / 2.0 delta_y = delta_height / 2.0 workspace_view = self.parentItemWithAttribute('units') if (workspace_view is not None): for other_unit in workspace_view.units: if ((other_unit is not self.unit) and (not isinstance(other_unit, unit.GroupUnit))): if (other_unit.x < self.unit.x): other_unit.x -= delta_x elif (other_unit.x > self.unit.x): other_unit.x += delta_x if (other_unit.y < self.unit.y): other_unit.y -= delta_y elif (other_unit.y > self.unit.y): other_unit.y += delta_y def layout(self): top_height = self.TOP_HEIGHT bottom_height = self.BOTTOM_HEIGHT # add a title label at the top if ((self.scene()) and (not self.title_proxy)): title_view = view.NameLabel(self.unit) self.title_proxy = self.scene().addWidget(title_view) self.title_proxy.setParentItem(self) r = self.boundingRect() r.adjust(1, 1, -1, -1) if (self.title_proxy): title_view = self.title_proxy.widget() title_view.setFixedWidth(r.width() - (2 * top_height)) title_height = title_view.geometry().height() self.title_proxy.setPos( QPointF(top_height, (top_height - title_height) / 2.0)) # make a button to delete the unit if (self.allow_delete): if ((self.scene()) and (not self._delete_button)): self._delete_button = DeleteButton(self) self._delete_button.clicked.connect(self.on_delete) if (self._delete_button): self._delete_button.setRect( QRectF(r.right() - top_height, r.top(), top_height, top_height)) elif (self._delete_button): self._delete_button.destroy() self._delete_button = None # make a button to add to the unit if (self.allow_add): if ((self.scene()) and (not self._add_button)): self._add_button = AddButton(self) self._add_button.clicked.connect(self.on_add) if (self._add_button): self._add_button.setRect( QRectF(r.left(), r.bottom() - bottom_height, bottom_height, bottom_height)) elif (self._add_button): self._add_button.destroy() self._add_button = None # make a button to drag the unit if ((self.scene()) and (not self._drag_button)): self._drag_button = DragButton(self, self.unit) if (self._drag_button): self._drag_button.setRect( QRectF(r.left(), r.top(), top_height, top_height)) # make a button to resize the unit if ((self.allow_resize_width) or (self.allow_resize_height)): if ((self.scene()) and (not self._resize_button)): self._resize_button = ResizeButton(self, target=self.unit, horizontal=self.allow_resize_width, vertical=self.allow_resize_height) self._resize_button.resize.connect(self.on_resize) if (self._resize_button): self._resize_button.setRect( QRectF(r.right() - bottom_height, r.bottom() - bottom_height, bottom_height, bottom_height)) elif (self._resize_button): self._resize_button.resize.disconnect(self.on_resize) self._resize_button.destroy() self._resize_button = None # position the content, if any m = self.MARGIN content_pos = QPointF(m, m + top_height) content_height = 0.0 if (self._content): self._content.setPos(content_pos) content_height = self._content.boundingRect().height() # position inputs and outputs left and right of the content io_rect = QRectF(0.0, content_pos.y(), r.width(), content_height) if (self._input_layout): self._input_layout.setRect(io_rect) if (self._output_layout): self._output_layout.setRect(io_rect) # draw a box enclosing the content and title def _paint(self, qp): pen = self.pen() pen.setWidth(2.0) qp.setPen(pen) if (self.unit.selected): qp.setBrush(self.brush(0.30)) elif (self.unit.hue is not None): color = QColor() color.setHsvF(self.unit.hue, 1.0, 1.0, 0.30) qp.setBrush(QBrush(color)) else: qp.setBrush(self.brush(0.15)) r = self.boundingRect() r.adjust(1, 1, -1, -1) qp.drawRoundedRect(r, 4.0, 4.0)