def drawTokenTag(self, br: QRectF, painter: 'QPainter'): """ This is a helper function for the paint function. It renders "Token Tags" in the corners of the GUI Components displayed in the TGUIM View. Token Tags show how many Tokens are associated with the associated component. :param br: The bounding rectangle of the component. :type br: QRectF :param painter: A QPainter object. :type painter: QPainter :return: None :rtype: NoneType """ if br.width() >= ComponentGraphics.TITLEBAR_H: token_count = str(self.getNumberOfTokens()) ttX = br.x() + br.width() - ComponentGraphics.TITLEBAR_H ttY = br.y() ttWidth = ComponentGraphics.TITLEBAR_H ttHeight = ComponentGraphics.TITLEBAR_H rectBox = QRectF(ttX, ttY, ttWidth, ttHeight) tokenTagFont = QFont("Times", 10) painter.setFont(tokenTagFont) painter.setBrush(QColor(255, 0, 0, 127)) #painter.drawRect(rectBox) painter.drawEllipse(rectBox.center(), ttWidth / 2 - 1, ttHeight / 2 - 1) painter.setBrush(QColor(100, 200, 255)) fm = QFontMetricsF(tokenTagFont) pixelsWide = fm.width(token_count) pixelsHigh = fm.height() painter.drawText(ttX + ttWidth / 2 - pixelsWide / 2, ttY + ttHeight / 2 + pixelsHigh / 4, token_count)
def styleChange(self): super().styleChange() style = self.style() # Text item ---------------------------------------------------------------------------------------------------- self._text_item.setFont(style.font(Style.MessageTextFont)) self._text_item.setMaximumWidth(style.pixelMetric(Style.MessageTextLength)) # Position text_metrics = QFontMetricsF(self._text_item.font()) icon_size = style.pixelMetric(Style.MessageIconSize) margin = style.pixelMetric(Style.MessageIconTextMargin) self._text_item.setPos(icon_size + margin, 0) self._text_item.moveBy(0, text_metrics.capHeight() / 2) self._text_item.moveBy(0, icon_size / 2) # Icon item ---------------------------------------------------------------------------------------------------- icon_renderer = self._icon_item.renderer() if icon_renderer is None: # No icon set scale = 1 else: scale = icon_size / icon_renderer.defaultSize().width() self._icon_item.setScale(scale)
def adjust(self): """Adjust the item's geometry in response to changes.""" metrics = QFontMetricsF(self.font()) # Get bounding rectangle for full text self._bounding_rect = metrics.boundingRect(self.text()) # Constrain by maximum width if self.maximumWidth() is not None: self._bounding_rect.setWidth(self.maximumWidth()) # Compute elided text self._elided_text = metrics.elidedText(self.text(), self.elideMode(), self.boundingRect().width()) # Get bounding rectangle for elided text self._bounding_rect = metrics.boundingRect(self.elidedText()) # It seems that for small characters like "..." the bounding rect returned is too small. Adjust it by a small # value. metrics_correction = px(1 / 72) self._bounding_rect.adjust(-metrics_correction, 0, metrics_correction, 0) # Move origin point according to the alignment if self.alignMode() & Qt.AlignLeft: self._bounding_rect.moveLeft(0) elif self.alignMode() & Qt.AlignRight: self._bounding_rect.moveRight(0) else: self._bounding_rect.moveLeft(-self._bounding_rect.width() / 2) # Set background rect self.background.setRect(self.boundingRect())
def __init__(self, parent_node: Node, flow, config=None): super(NodeInstance, self).__init__() self.parent_node = parent_node self.flow = flow # general attributes self.inputs = [] self.outputs = [] self.main_widget = None self.main_widget_proxy: FlowProxyWidget = None self.default_actions = { 'remove': { 'method': self.action_remove, 'data': 123 }, 'compute shape': { 'method': self.compute_content_positions } } # holds information for context menus self.gen_data_on_request = False self.personal_logs = [] self.special_actions = { } # only gets written in custom NodeInstance-subclasses - dynamic self.width = -1 self.height = -1 self.display_name_font = QFont('Poppins', 15) if parent_node.design_style == 'extended' else \ QFont('K2D', 20, QFont.Bold, True) self.display_name_FM = QFontMetricsF(self.display_name_font) # self.port_label_font = QFont("Source Code Pro", 10, QFont.Bold, True) # gets set to false a few lines below. needed for setup ports (to prevent shape updating stuff) self.initializing = True self.temp_state_data = None if self.parent_node.has_main_widget: self.main_widget = self.parent_node.main_widget_class(self) self.main_widget_proxy = FlowProxyWidget(self.flow, self) self.main_widget_proxy.setWidget(self.main_widget) if config: # self.setPos(config['position x'], config['position y']) self.setup_ports(config['inputs'], config['outputs']) if self.main_widget: try: self.main_widget.set_data(config['main widget data']) except KeyError: pass self.special_actions = self.set_special_actions_data( config['special actions']) self.temp_state_data = config['state data'] else: self.setup_ports() # TOOLTIP self.setToolTip(self.parent_node.description) self.initializing = False
def _manage_font_cache(real_font, font, metrics, height, width, ascent): if real_font == font: return font, metrics, height, width, ascent metrics = QFontMetricsF(real_font) height = metrics.height() width = metrics.width('A') ascent = metrics.ascent() return real_font, metrics, height, width, ascent
def __init__(self, parent): QItemDelegate.__init__(self, parent) self.font = binaryninjaui.getMonospaceFont(parent) self.font.setKerning(False) self.baseline = QFontMetricsF(self.font).ascent() self.char_width = binaryninjaui.getFontWidthAndAdjustSpacing(self.font)[0] self.char_height = QFontMetricsF(self.font).height() self.char_offset = binaryninjaui.getFontVerticalOffset() self.expected_char_widths = [10, 32]
def styleChange(self): super().styleChange() self.prepareGeometryChange() style = self.style() margin = style.pixelMetric(Style.ConnectionStemTextMargin) metrics = QFontMetricsF(self._text_item.font()) self._stem_item.setLine(QLineF(self.stemRoot(), self.stemTip())) self._text_item.setPos(self.stemTip().x() + margin, metrics.capHeight() / 2)
def __init__(self, parent_port_instance, parent_node_instance): super(PortInstanceLabel, self).__init__(parent_node_instance) self.parent_port_instance = parent_port_instance self.parent_node_instance = parent_node_instance self.font = QFont("Source Code Pro", 10, QFont.Bold) font_metrics = QFontMetricsF(self.font) self.width = font_metrics.width( get_longest_line(self.parent_port_instance.label_str)) self.height = font_metrics.height() * ( self.parent_port_instance.label_str.count('\n') + 1) self.port_local_pos = None
def init_font_config(self): self.disasm_font = QFont("DejaVu Sans Mono", 10) font_metrics = QFontMetricsF(self.disasm_font) self.disasm_font_height = font_metrics.height() self.disasm_font_width = font_metrics.width('A') self.disasm_font_ascent = font_metrics.ascent() self.symexec_font = QFont("DejaVu Sans Mono", 10) font_metrics = QFontMetricsF(self.symexec_font) self.symexec_font_height = font_metrics.height() self.symexec_font_width = font_metrics.width('A') self.symexec_font_ascent = font_metrics.ascent()
def __init__(self, parent_port_instance, parent_node_instance): super(PortInstanceLabel, self).__init__(parent_node_instance) self.setGraphicsItem(self) self.parent_port_instance = parent_port_instance self.parent_node_instance = parent_node_instance self.font = QFont("Source Code Pro", 10, QFont.Bold) font_metrics = QFontMetricsF( self.font) # approximately! the designs can use different fonts self.width = font_metrics.width( get_longest_line(self.parent_port_instance.label_str)) self.height = font_metrics.height() * ( self.parent_port_instance.label_str.count('\n') + 1) self.port_local_pos = None
def __init__(self, parent_port_instance, parent_node_instance): super(PortInstanceLabel, self).__init__(parent_node_instance) self.setGraphicsItem(self) self.parent_port_instance = parent_port_instance self.parent_node_instance = parent_node_instance self.font = QFont("Source Code Pro", 10, QFont.Bold) font_metrics = QFontMetricsF(self.font) self.width = font_metrics.width( get_longest_line(self.parent_port_instance.label_str)) self.height = font_metrics.height() * ( self.parent_port_instance.label_str.count('\n') + 1) # print('self.height:', self.height) # self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.port_local_pos = None
def drawText(self, painter: QPainter) -> None: painter.save() painter.setPen(Qt.NoPen) font: QFont = QFont() font.setBold(True) font.setPointSize(10) painter.setFont(font) now: QDateTime = QDateTime.currentDateTime() fm: QFontMetricsF = QFontMetricsF(font) textList: List[AnyStr] = [ now.toString("MM月dd日yyyy"), now.toString("hh:mm:ss.zzz") ] # 绘制文本路径 textPath: QPainterPath = QPainterPath() textPath.addText(-fm.width(textList[0]) / 2.0, -fm.lineSpacing() / 2.0, font, textList[0]) textPath.addText(-fm.width(textList[1]) / 2.0, fm.lineSpacing() / 2.0, font, textList[1]) strokeColor: QColor = self.__textColor.light(80) strokeColor.setAlphaF(0.2) painter.strokePath( textPath, QPen(strokeColor, self.__shadowWidth, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.setBrush(self.__textColor) painter.drawPath(textPath) painter.restore()
def __call__(self, point_size): qt_font = font_db.font(self.name, "Roman", point_size) return Font( qt_font, QFontMetricsF(qt_font, self.renderer.writer), self.renderer.writer.resolution(), )
def __init__(self, parent_node_instance): super(TitleLabel, self).__init__(parent_node_instance) self.setGraphicsItem(self) self.parent_node_instance: NodeInstance = parent_node_instance self.title_str = self.parent_node_instance.parent_node.title self.font = QFont('Poppins', 15) if self.parent_node_instance.parent_node.design_style == 'extended' else \ QFont('K2D', 20, QFont.Bold, True) self.fm = QFontMetricsF(self.font) self.width = self.fm.width(get_longest_line(self.title_str)) self.height = self.fm.height() * 0.7 * (self.title_str.count('\n') + 1) self.color = QColor(30, 43, 48) self.pen_width = 1.5 self.hovering = False # whether the mouse is hovering over the parent NI (!)
def styleChange(self): self.prepareGeometryChange() style = self.style() # Size and Frame frame_width = style.pixelMetric(Style.NodeWidth) self._size.setWidth(frame_width) self._body_item.setPen(style.framePen(self.palette())) path = QPainterPath() path.addRoundedRect(QRectF(QPointF(), self.size()), style.pixelMetric(Style.NodeFrameCornerRadius), style.pixelMetric(Style.NodeFrameCornerRadius)) self._body_item.setPath(path) # Title item title_font = style.font(Style.NodeTitleFont) title_metrics = QFontMetricsF(title_font) padding = style.pixelMetric(Style.NodeFrameTextPadding) self._title_item.setFont(title_font) self._title_item.setPos(padding, padding) self._title_item.moveBy(0, title_metrics.capHeight()) self._title_item.setMaximumWidth(frame_width - padding * 2) # Divider item div_margin = style.pixelMetric(Style.NodeDividerTextMargin) div_voffset = padding + title_metrics.capHeight( ) + title_metrics.descent() + div_margin self._divider.setLine(0, div_voffset, frame_width, div_voffset) self._divider.setPen(style.framePen(self.palette())) # Description item self._description_item.setFont(style.font(Style.NodeDescriptionFont)) self._description_item.setPos(padding, div_voffset + div_margin) self._description_item.setFrame( QRectF( QPointF(0, 0), QSizeF( px(frame_width) - padding * 2, (px(self.size().height()) - padding) - (div_voffset + padding))))
def __init__(self, parent_node_instance): super(TitleLabel, self).__init__(parent_node_instance) self.setGraphicsItem(self) self.parent_node_instance = parent_node_instance self.title_str = self.parent_node_instance.parent_node.title font = QFont('Poppins', 15) if self.parent_node_instance.parent_node.design_style == 'extended' else \ QFont('K2D', 20, QFont.Bold, True) # should be quite similar to every specific font chosen by the painter fm = QFontMetricsF(font) # approximately! self.width = fm.width(get_longest_line(self.title_str) + '___') self.height = fm.height() * 0.7 * (self.title_str.count('\n') + 1) self.color = QColor(30, 43, 48) self.pen_width = 1.5 self.hovering = False # whether the mouse is hovering over the parent NI (!) # Design.flow_theme_changed.connect(self.theme_changed) self.update_design()
def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, index: QWidget) -> None: """ Paint the graphics of the action wrapper including action name, number, and ports. :param painter: This draws the widget. :type painter: QPainter :param option: Option for the style of graphic. :type option: QStyleOptionGraphicsItem :param index: Index for the painted graphic. :type index: QWidget :return: None :rtype: NoneType """ ActionGraphics.paint(self, painter, option, index) # Get dimensions of the action x, y, width, height = self.getActionRect(self._action.getInputPorts(), self._action.getOutputPorts()) # Draw the number tag. number = str( self._action.getParent().getActions().index(self._action) + 1) offset = 5 radius = 15 size = ActionGraphics.H_SPACE / 2 - offset * 2 painter.setBrush(QColor(29, 110, 37)) painter.drawRoundedRect(QRectF(x + offset, y + offset, size, size), radius, radius) painter.setPen(ActionWrapperGraphics.TAG_TEXT_COLOR) painter.setBrush(ActionWrapperGraphics.TAG_TEXT_COLOR) painter.setFont(ActionWrapperGraphics.TAG_FONT) fm = QFontMetricsF(ActionWrapperGraphics.TAG_FONT) pixelsWide = fm.width(number) pixelsHigh = fm.height() # TODO: fix text positioning - font metrics aren't working well painter.drawText(x + offset + size / 2 - pixelsWide, y + offset + size / 2 + pixelsHigh / 2, number) # Draw the name of the action painter.setPen(ActionWrapperGraphics.NAME_TEXT_COLOR) painter.setBrush(ActionWrapperGraphics.NAME_TEXT_COLOR) painter.setFont(ActionWrapperGraphics.NAME_FONT) fm = QFontMetricsF(ActionWrapperGraphics.NAME_FONT) br = fm.boundingRect(self._action.getName()) # TODO: fix text positioning - font metrics aren't working well t = fm.elidedText(self._action.getName(), Qt.ElideRight, self._width - offset * 2) painter.drawText(x + offset, br.height(), t)
def paintEvent(self, ev): """ Manually implemented paint event :param ev: the QT paint event :return: """ h = self.height() w = self.width() p = QPainter(self) p.setClipRect(ev.region().boundingRect()) pen = QPen(QColor(0, 0, 0)) pen.setWidth(4) ls = QFontMetricsF(p.font()).lineSpacing() for idx, t in enumerate(sorted(list(self._loadData.keys()))): y = 10 + idx * ls pen.setColor(ThreadToColor.singleton.get(t)) p.setPen(pen) p.drawLine(QLineF(15, y, 15 + 15, y)) pen.setColor(QColor(0, 0, 0)) p.setPen(pen) p.drawText(QPointF(35, y), t) if len(self._loadData) > 0: right = max([ polygon[polygon.count() - 1].x() for _, polygon in self._loadData.items() ]) else: right = 0.0 p.translate(w - 10 - right * 20, h - 10) p.scale( 20, -(h - 20) ) # x direction: 20 pixels per second, y direction: spread between 10 and h-10 topleft = p.transform().inverted()[0].map(QPointF(10, 10)) pen.setWidthF(0) pen.setCosmetic(True) left = topleft.x() p.setRenderHint(QPainter.Antialiasing, True) p.setPen(pen) p.drawLine(QLineF(left, 0, right, 0)) p.drawLine(QLineF(left, 0, left, 1)) idx = 0 for t, polygon in self._loadData.items(): pen.setColor(ThreadToColor.singleton.get(t)) p.setPen(pen) p.drawPolyline(polygon) p.end()
def _init_font_interface(cls): ''' static init interface, font family and font size have to be set first. This function does not have to be called. ''' # should move to main # workaround if cls._app is None: try: cls._app = QApplication(sys.argv) except RuntimeError: cls._app = False if (cls.font_size is not None and cls.font_family is not None): cls.font = QFont(cls.font_family, cls.font_size) cls.font_metrics = QFontMetricsF(cls.font, QSvgGenerator())
def __init__(self, parent, name): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) font = getMonospaceFont(self) fm = QFontMetricsF(font) table_layout = QVBoxLayout() self.table = QTableView() self.table.setFont(font) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.verticalHeader().hide() self.table.verticalHeader().setSectionResizeMode(QHeaderView.Fixed) self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # sorting self.table.setSortingEnabled(True) self.table.horizontalHeader().setSortIndicator(0, QtCore.Qt.AscendingOrder) data = [] self.model = TableModel(data) self.table.setModel(self.model) table_layout.addWidget(self.table) layout = QVBoxLayout() layout.addLayout(table_layout) self.setLayout(layout) # init double click action self.table.doubleClicked.connect(self._ui_entry_double_click) # init right click menu self.ctx_menu = QMenu() self._action_patch = QAction("Invert Branch", None) self.ctx_menu.addAction(self._action_patch) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self._ui_table_ctx_menu_handler) self.bv = None self.filename = None self.do_sync = True
def __init__(self, port: 'Port', parent: QGraphicsItem = None, menuEnabled: bool = True): """ Constructs a portGraphics object for the given Port object. :param port: The port for which this graphics item represents. :type port: Port :param parent: A QGraphicsItem (probably an actionGraphics object) :type parent: QGraphicsItem :param menuEnabled: If true, a context menu will be shown on right-click. :type menuEnabled: bool """ QGraphicsItem.__init__(self, parent) self.setAcceptDrops(True) self.setFlag(QGraphicsItem.ItemIsSelectable) self._port = port self._menuEnabled = menuEnabled self.menu = PortMenu() # If port is required and it's an input, make the border thicker if not self._port.isOptional() and self._port in self._port.getAction( ).getInputPorts(): self.borderWidth = PortGraphics.REQUIRED_PEN_WIDTH else: self.borderWidth = PortGraphics.OPTIONAL_PEN_WIDTH # show port name and type if self._menuEnabled: fm = QFontMetricsF(PortGraphics.NAME_FONT) name = fm.elidedText(self._port.getName(), Qt.ElideRight, PortGraphics.SIDE_HEIGHT) self.nameItem = QGraphicsTextItem(name, self) self.nameItem.setFont(PortGraphics.NAME_FONT) self.nameItem.setRotation(90) self.nameItem.setPos(PortGraphics.WIDTH / 2 + 5, -PortGraphics.TOTAL_HEIGHT / 2) fm = QFontMetricsF(PortGraphics.TYPE_FONT) t = fm.elidedText(self._port.getDataType().__name__, Qt.ElideRight, PortGraphics.SIDE_HEIGHT) self.typeItem = QGraphicsTextItem(t, self) self.typeItem.setFont(PortGraphics.TYPE_FONT) self.typeItem.setRotation(90) self.typeItem.setPos(5, -PortGraphics.TOTAL_HEIGHT / 2)
def __init__(self): ptrs.append(self) self.windowMain = wrapInstance(long(OpenMayaUI_v1.MQtUtil.mainWindow()), QMainWindow) super(ToolSeq_Formula, self).__init__(self.windowMain) self.window = ToolSeq_Formula.qUiLoader.load(ToolSeq_Formula.userScriptDir + 'ToolSeq_Formula.ui', self) self.window.destroyed.connect(lambda: ptrs_remove(self)) self.window.setWindowFlags(self.window.windowFlags() & ~Qt.WindowMinMaxButtonsHint) self.window.setAttribute(Qt.WA_DeleteOnClose) for qComboBox in self.window.findChildren(QComboBox): qComboBox.setItemDelegate(QStyledItemDelegate(qComboBox)) with open(ToolSeq_Formula.userScriptDir + 'ToolSeq.qss', 'r') as fileStyleSheet: self.window.setStyleSheet(fileStyleSheet.read()) font = QFont('Consolas', 9) font.setStyleHint(QFont.Monospace) self.window.Text_PreFormula.setFont(font) self.window.Text_Formula.setFont(font) fontTab = QFontMetricsF(font).horizontalAdvance(' ') * 4 self.window.Text_PreFormula.setTabStopDistance(fontTab) self.window.Text_Formula.setTabStopDistance(fontTab) self.window.Text_PreFormula.setPlainText(ToolSeq_Formula.preFormulas[11]) self.window.Text_Formula.setPlainText(ToolSeq_Formula.formulas[11]) self.window.Widget_Shape.installEventFilter(self) self.window.Check_VariableN.toggled.connect(self.Event_VariableN) self.window.Button_Fill.installEventFilter(self) self.window.Button_Formulate.installEventFilter(self) self.window.show() wMax = max(self.window.Label_1.width(), self.window.Label_2.width()) self.window.Label_1.setFixedWidth(wMax) self.window.Label_2.setFixedWidth(wMax) maya_cmds.loadPlugin('ToolSeq_Formula.py', quiet=True)
def init_font_config(self): self.ui_default_font = QGuiApplication.font() self.disasm_font = QFont("DejaVu Sans Mono", 10) self.disasm_font_metrics = QFontMetricsF(self.disasm_font) self.disasm_font_height = self.disasm_font_metrics.height() self.disasm_font_width = self.disasm_font_metrics.width('A') self.disasm_font_ascent = self.disasm_font_metrics.ascent() self.symexec_font = QFont("DejaVu Sans Mono", 10) self.symexec_font_metrics = QFontMetricsF(self.symexec_font) self.symexec_font_height = self.symexec_font_metrics.height() self.symexec_font_width = self.symexec_font_metrics.width('A') self.symexec_font_ascent = self.symexec_font_metrics.ascent() self.code_font = QFont("Source Code Pro", 10) self.code_font_metrics = QFontMetricsF(self.code_font) self.code_font_height = self.code_font_metrics.height() self.code_font_width = self.code_font_metrics.width('A') self.code_font_ascent = self.code_font_metrics.ascent()
class TitleLabel(QGraphicsWidget): def __init__(self, parent_node_instance): super(TitleLabel, self).__init__(parent_node_instance) self.setGraphicsItem(self) self.parent_node_instance = parent_node_instance self.title_str = self.parent_node_instance.parent_node.title self.font = QFont('Poppins', 15) if self.parent_node_instance.parent_node.design_style == 'extended' else \ QFont('K2D', 20, QFont.Bold, True) self.fm = QFontMetricsF(self.font) self.width = self.fm.width(get_longest_line(self.title_str)+'___') self.height = self.fm.height() * 0.7 * (self.title_str.count('\n') + 1) self.color = QColor(30, 43, 48) self.pen_width = 1.5 self.hovering = False # whether the mouse is hovering over the parent NI (!) # Design.flow_theme_changed.connect(self.theme_changed) self.update_design() def boundingRect(self): return QRectF(QPointF(0, 0), self.geometry().size()) def setGeometry(self, rect): self.prepareGeometryChange() QGraphicsLayoutItem.setGeometry(self, rect) self.setPos(rect.topLeft()) def sizeHint(self, which, constraint=...): return QSizeF(self.width, self.height) def paint(self, painter, option, widget=None): pen = QPen(self.color) pen.setWidth(self.pen_width) painter.setPen(pen) painter.setFont(self.font) text_rect = self.boundingRect() text_rect.setTop(text_rect.top()-7) if self.design_style() == 'extended': painter.drawText(text_rect, Qt.AlignTop, self.title_str) elif self.design_style() == 'minimalistic': painter.drawText(text_rect, Qt.AlignTop | Qt.AlignHCenter, self.title_str) def design_style(self): return self.parent_node_instance.parent_node.design_style def set_NI_hover_state(self, hovering: bool): self.hovering = hovering self.update_design() def theme_changed(self, new_theme): """Gets called from the parent node instance because the order of the different updates matters.""" # not working yet self.update_design() def update_design(self): theme = Design.flow_theme if self.design_style() == 'extended': if theme == 'dark std': if self.hovering: self.color = self.parent_node_instance.color.lighter() self.pen_width = 2 else: self.color = QColor(30, 43, 48) self.pen_width = 1.5 elif theme == 'dark tron' or theme == 'ghostly': if self.hovering: self.color = self.parent_node_instance.color.lighter() else: self.color = self.parent_node_instance.color self.pen_width = 2 elif theme == 'blender': self.color = QColor('#ffffff') elif self.design_style() == 'minimalistic': if theme == 'dark std': if self.hovering: self.color = self.parent_node_instance.color.lighter() self.pen_width = 1.5 else: self.color = QColor(30, 43, 48) self.pen_width = 1.5 elif theme == 'dark tron' or theme == 'ghostly' or theme == 'blender': self.color = self.parent_node_instance.color self.pen_width = 2 self.update() # ANIMATION STUFF def get_color(self): return self.color def set_color(self, val): self.color = val QGraphicsItem.update(self) p_color = Property(QColor, get_color, set_color)
def setUp(self): super(QFontMetricsFTest, self).setUp() self.font = QFont() self.metrics = QFontMetricsF(self.font)
def __init__(self, parent_node: Node, flow, config=None): super(NodeInstance, self).__init__() self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemSendsScenePositionChanges) self.setAcceptHoverEvents(True) # GENERAL ATTRIBUTES self.parent_node = parent_node self.flow = flow self.movement_state = None self.movement_pos_from = None self.inputs = [] self.outputs = [] self.main_widget = None self.main_widget_proxy: FlowProxyWidget = None self.default_actions = { 'remove': { 'method': self.action_remove, 'data': 123 }, 'compute shape': { 'method': self.compute_content_positions } } # for context menus self.gen_data_on_request = False self.personal_logs = [] self.special_actions = { } # only gets written in custom NodeInstance-subclasses - dynamic self.width = -1 self.height = -1 self.display_name_font = QFont('Poppins', 15) if parent_node.design_style == 'extended' else \ QFont('K2D', 20, QFont.Bold, True) self.display_name_FM = QFontMetricsF(self.display_name_font) # self.port_label_font = QFont("Source Code Pro", 10, QFont.Bold, True) # 'initializing' will be set to False below. It's needed for the ports setup, to prevent shape updating stuff self.initializing = True self.temp_state_data = None if self.parent_node.has_main_widget: self.main_widget = self.parent_node.main_widget_class(self) self.main_widget_proxy = FlowProxyWidget(self.flow, self) self.main_widget_proxy.setWidget(self.main_widget) if config: # self.setPos(config['position x'], config['position y']) self.setup_ports(config['inputs'], config['outputs']) if self.main_widget: try: self.main_widget.set_data(config['main widget data']) except KeyError: pass self.special_actions = self.set_special_actions_data( config['special actions']) self.temp_state_data = config['state data'] else: self.setup_ports() # TOOLTIP self.setToolTip(self.parent_node.description) self.setCursor(Qt.SizeAllCursor) self.initializing = False
class TitleLabel(QGraphicsWidget): def __init__(self, parent_node_instance): super(TitleLabel, self).__init__(parent_node_instance) self.setGraphicsItem(self) self.parent_node_instance: NodeInstance = parent_node_instance self.title_str = self.parent_node_instance.parent_node.title self.font = QFont('Poppins', 15) if self.parent_node_instance.parent_node.design_style == 'extended' else \ QFont('K2D', 20, QFont.Bold, True) self.fm = QFontMetricsF(self.font) self.width = self.fm.width(get_longest_line(self.title_str)) self.height = self.fm.height() * 0.7 * (self.title_str.count('\n') + 1) self.color = QColor(30, 43, 48) self.pen_width = 1.5 self.hovering = False # whether the mouse is hovering over the parent NI (!) def boundingRect(self): return QRectF(QPointF(0, 0), self.geometry().size()) def setGeometry(self, rect): self.prepareGeometryChange() QGraphicsLayoutItem.setGeometry(self, rect) self.setPos(rect.topLeft()) def sizeHint(self, which, constraint=...): return QSizeF(self.width, self.height) def paint(self, painter, option, widget=None): self.set_design() pen = QPen(self.color) pen.setWidth(self.pen_width) painter.setPen(pen) painter.setFont(self.font) text_rect = self.boundingRect() text_rect.setTop(text_rect.top()-7) painter.drawText(text_rect, Qt.AlignTop, self.title_str) def design_style(self): return self.parent_node_instance.parent_node.design_style def set_NI_hover_state(self, hovering: bool): self.hovering = hovering self.update() def set_design(self): if self.design_style() == 'extended': if Design.flow_style == 'dark std': if self.hovering: self.color = self.parent_node_instance.parent_node.color.lighter() self.pen_width = 2 else: self.color = QColor(30, 43, 48) self.pen_width = 1.5 elif Design.flow_style == 'dark tron': if self.hovering: self.color = self.parent_node_instance.parent_node.color.lighter() else: self.color = self.parent_node_instance.parent_node.color self.pen_width = 2 elif self.design_style() == 'minimalistic': if Design.flow_style == 'dark std': if self.hovering: self.color = self.parent_node_instance.parent_node.color.lighter() self.pen_width = 1.5 else: self.color = QColor(30, 43, 48) self.pen_width = 1.5 elif Design.flow_style == 'dark tron': self.color = self.parent_node_instance.parent_node.color self.pen_width = 2
def __init__(self, scene, splash=None, app=None): if app is None: if QtWidgets.QApplication.instance() is not None: self.app = QtWidgets.QApplication.instance() else: self.app = QtWidgets.QApplication() else: self.app = app self.app.aboutToQuit.connect(self.onClose) if splash is None: splash = QtWidgets.QSplashScreen() splash.setPixmap(QPixmap(":/icons/splashscreen.png")) splash.show() # Main Window self.MainWindow = QtWidgets.QMainWindow() self.ui = Ui_MainWindow() self.ui.setupUi(self.MainWindow) # ============== private properties ================ self._codelog = [] self._animation_start_time = time.time() """Time at start of the simulation in seconds (system-time)""" self._animation_length = 0 """The length of the animation in seconds""" self._animation_loop = False """Animation is a loop""" self._animation_final_dofs = None """DOFS at termination of the animation""" self._animation_keyframe_interpolation_object = None """Object that can be called with a time and yields the dofs at that time. t should be [0..._animation_length] """ self._animation_paused = False """Animation paused""" self._animation_available = False """Animation available""" self._animation_speed = 1.0 # ================= Create globally available properties ======= self.selected_nodes = [] """A list of selected nodes (if any)""" self.scene = scene """Reference to a scene""" # ======================== Create 3D viewpower ==================== self.visual = Viewport(scene) """Reference to a viewport""" self.visual.create_visuals(recreate=True) self.visual.mouseLeftEvent = self.view3d_select_element self.visual.show_embedded(self.ui.frame3d) self.visual.position_visuals() self.visual.update_visibility() # right-click event for self.ui.frame3d.setContextMenuPolicy(Qt.CustomContextMenu) self.ui.frame3d.customContextMenuRequested.connect( self.rightClickViewport) self._timerid = None iren = self.visual.renwin.GetInteractor() iren.AddObserver('TimerEvent', self.timerEvent) # ------ key-presses ----- self.visual.onEscapeKey = self.escPressed # ------ viewport buttons ------ self.ui.btnWater.pressed.connect(self.toggle_show_global) self.ui.btnBlender.pressed.connect(self.to_blender) # ------ animation buttons ------ self.ui.frameAni.setVisible(False) self.ui.btnStopAnimation.pressed.connect( lambda: self.animation_terminate(False)) self.ui.btnPauseAnimation.pressed.connect( self.animation_pause_or_continue_click) self.ui.aniSlider.valueChanged.connect(self.animation_change_time) self.ui.sbPlaybackspeed.valueChanged.connect( self.animation_speed_change) # ======================== Main Menu entries :: visuals ====== self.ui.actionNew.triggered.connect(self.clear) self.ui.actionOpen.triggered.connect(self.open) self.ui.actionSave_scene.triggered.connect(self.menu_save) self.ui.actionSave_actions_as.triggered.connect(self.menu_save_actions) self.ui.actionImport_sub_scene.triggered.connect(self.menu_import) self.ui.actionImport_browser.triggered.connect(self.import_browser) # --- buttons self.ui.pbExecute.pressed.connect(self.run_code_in_teCode) self.ui.pbCopyOutput.pressed.connect(self.feedback_copy) self.ui.pbCopyHistory.pressed.connect(self.history_copy) self.ui.pbGenerateSceneCode.pressed.connect(self.generate_scene_code) self.ui.pbClearCode.pressed.connect(self.clear_code) # self.ui.btnSolveStatics.clicked.connect(self.solve_statics) self.ui.btnUndoStatics.clicked.connect(self.undo_solve_statics) # -- visuals self.ui.actionShow_water_plane.triggered.connect( self.toggle_show_global_from_menu) self.ui.actionShow_visuals.triggered.connect(self.toggle_show_visuals) self.ui.actionShow_Geometry_elements.triggered.connect( self.toggle_show_geometry) self.ui.actionShow_force_applyting_element.triggered.connect( self.toggle_show_force) self.ui.actionHorizontal_camera.triggered.connect( self.visual.level_camera) self.ui.actionAdd_light.triggered.connect(self.visual.make_lighter) self.ui.actionDark_mode.triggered.connect(self.visual.make_darker) self.ui.action2D_mode.triggered.connect(self.visual.toggle_2D) self.ui.actionX.triggered.connect(lambda: self.camera_set_direction( (1, 0, 0))) self.ui.action_x.triggered.connect(lambda: self.camera_set_direction( (-1, 0, 0))) self.ui.actionY.triggered.connect(lambda: self.camera_set_direction( (0, 1, 0))) self.ui.action_Y.triggered.connect(lambda: self.camera_set_direction( (0, -1, 0))) self.ui.actionZ.triggered.connect(lambda: self.camera_set_direction( (0, 0, -1))) self.ui.action_Z.triggered.connect(lambda: self.camera_set_direction( (0, 0, 1))) self.ui.actionCamera_reset.triggered.connect(self.camera_reset) # def normalize_force(): self.run_code( 'self.visual.force_do_normalize = not self.visual.force_do_normalize', guiEventType.VIEWER_SETTINGS_UPDATE) self.ui.actionShow_all_forces_at_same_size.triggered.connect( normalize_force) def increase_force_size(): self.run_code( 'self.visual.force_scale = 1.1*self.visual.force_scale', guiEventType.VIEWER_SETTINGS_UPDATE) self.ui.actionIncrease_force_size.triggered.connect( increase_force_size) def decrease_force_size(): self.run_code( 'self.visual.force_scale = 0.9*self.visual.force_scale', guiEventType.VIEWER_SETTINGS_UPDATE) self.ui.actionDecrease_force_size.triggered.connect( decrease_force_size) def increase_geo_size(): self.run_code( 'self.visual.geometry_scale = 1.1*self.visual.geometry_scale', guiEventType.VIEWER_SETTINGS_UPDATE) self.ui.actionIncrease_Geometry_size.triggered.connect( increase_geo_size) def decrease_geo_size(): self.run_code( 'self.visual.geometry_scale = 0.9*self.visual.geometry_scale', guiEventType.VIEWER_SETTINGS_UPDATE) self.ui.actionDecrease_Geometry_size.triggered.connect( decrease_geo_size) # ======================= Code-highlighter ============== font = QFont() font.setPointSize(10) font.setFamily('Consolas') self.ui.teCode.setFont(font) self.ui.teCode.setTabStopDistance( QFontMetricsF(self.ui.teCode.font()).width(' ') * 4) self.highlight = PythonHighlighter(self.ui.teCode.document()) self.eventFilter = CtrlEnterKeyPressFilter() self.eventFilter.callback = self.run_code_in_teCode self.ui.teCode.installEventFilter(self.eventFilter) # ======================== Docks ==================== self.guiWidgets = dict() """Dictionary of all created guiWidgets (dock-widgets)""" def set_pb_style(pb): pb.setFlat(True) pb.setCheckable(True) pb.setAutoExclusive(True) self.ui.toolBar.addWidget(pb) # Workspace buttons btnConstruct = QtWidgets.QPushButton() btnConstruct.setText('&0. Library') btnConstruct.clicked.connect(self.import_browser) btnConstruct.setFlat(True) self.ui.toolBar.addWidget(btnConstruct) btnConstruct = QtWidgets.QPushButton() btnConstruct.setText('&1. Construct') btnConstruct.clicked.connect( lambda: self.activate_workspace("CONSTRUCT")) set_pb_style(btnConstruct) btnConstruct.setChecked(True) btnConstruct = QtWidgets.QPushButton() btnConstruct.setText('&2. Explore') btnConstruct.clicked.connect( lambda: self.activate_workspace("EXPLORE")) set_pb_style(btnConstruct) btnConstruct = QtWidgets.QPushButton() btnConstruct.setText('&3. Ballast') btnConstruct.clicked.connect( lambda: self.activate_workspace("BALLAST")) set_pb_style(btnConstruct) btnConstruct = QtWidgets.QPushButton() btnConstruct.setText('&4. Stability') btnConstruct.clicked.connect( lambda: self.activate_workspace("STABILITY")) set_pb_style(btnConstruct) btnConstruct = QtWidgets.QPushButton() btnConstruct.setText('&5. Mode Shapes') btnConstruct.clicked.connect( lambda: self.activate_workspace("DYNAMICS")) set_pb_style(btnConstruct) btnConstruct = QtWidgets.QPushButton() btnConstruct.setText('&6. Airy') btnConstruct.clicked.connect(lambda: self.activate_workspace("AIRY")) set_pb_style(btnConstruct) space = QtWidgets.QWidget() space.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) self.ui.toolBar.addWidget(space) self.activate_workspace('CONSTRUCT') # ======================== Finalize ======================== splash.finish(self.MainWindow) self.MainWindow.show() self.app.exec_()
def compute_size_and_positions(self): """Very ugly: manually computes the geometry. Should get removed later when implemented using QGraphicsLayouts!""" self.width = 0 self.height = 0 gate_label_buffer = 10 # adds space between the gate and the label (vertical) label_widget_buffer = 10 label_FM = QFontMetricsF(self.label.font) self.width = self.gate.width + self.label.width + gate_label_buffer self.height = self.gate.height if self.gate.height > self.label.height else self.label.height self.height *= 1.3 if self.direction == 'input': if self.widget: widget_width = self.widget.width() widget_height = self.widget.height() if self.widget_pos == 'under': self.width = widget_width if widget_width > self.width else self.width self.height += widget_height upper_row_height = self.gate.height if self.gate.height > self.label.height else self.label.height self.widget.port_local_pos = QPointF( -self.width / 2 + self.widget.width() / 2, -self.height / 2 + upper_row_height + self.widget.height() / 2) self.gate.port_local_pos = QPointF( -self.width / 2 + self.gate.width / 2, -self.height / 2 + upper_row_height / 2) self.label.port_local_pos = QPointF( -self.width / 2 + self.gate.width + gate_label_buffer + self.label.width / 2, -self.height / 2 + upper_row_height / 2) elif self.widget_pos == 'besides': self.width += label_widget_buffer + widget_width self.height = self.height if self.height > self.widget.height( ) else self.widget.height() self.widget.port_local_pos = QPointF( -self.width / 2 + self.gate.width + gate_label_buffer + self.label.width + label_widget_buffer + self.widget.width() / 2, 0) self.gate.port_local_pos = QPointF( -self.width / 2 + self.gate.width / 2, 0) self.label.port_local_pos = QPointF( -self.width / 2 + self.gate.width + gate_label_buffer + self.label.width / 2, 0) if self.widget.width() > self.width: self.width = self.widget.width() else: self.gate.port_local_pos = QPointF( -self.width / 2 + self.gate.width / 2, 0) self.label.port_local_pos = QPointF( -self.width / 2 + self.gate.width + gate_label_buffer + self.label.width / 2, 0) elif self.direction == 'output': self.gate.port_local_pos = QPointF( +self.width / 2 - self.gate.width / 2, 0) self.label.port_local_pos = QPointF( +self.width / 2 - self.gate.width - gate_label_buffer - self.label.width / 2, 0)
class ConfigurationManager: __slots__ = ['_entries'] def __init__(self, entries=None): if entries is None: self._entries = {} for entry in ENTRIES: self._entries[entry.name] = entry.copy() else: self._entries = entries def init_font_config(self): self.ui_default_font = QGuiApplication.font() self.disasm_font = QFont("DejaVu Sans Mono", 10) self.disasm_font_metrics = QFontMetricsF(self.disasm_font) self.disasm_font_height = self.disasm_font_metrics.height() self.disasm_font_width = self.disasm_font_metrics.width('A') self.disasm_font_ascent = self.disasm_font_metrics.ascent() self.symexec_font = QFont("DejaVu Sans Mono", 10) self.symexec_font_metrics = QFontMetricsF(self.symexec_font) self.symexec_font_height = self.symexec_font_metrics.height() self.symexec_font_width = self.symexec_font_metrics.width('A') self.symexec_font_ascent = self.symexec_font_metrics.ascent() self.code_font = QFont("Source Code Pro", 10) self.code_font_metrics = QFontMetricsF(self.code_font) self.code_font_height = self.code_font_metrics.height() self.code_font_width = self.code_font_metrics.width('A') self.code_font_ascent = self.code_font_metrics.ascent() def __getattr__(self, item): if item in self.__slots__: raise AttributeError() if item in self._entries: return self._entries[item].value raise AttributeError(item) def __setattr__(self, key, value): if key in self.__slots__: super(ConfigurationManager, self).__setattr__(key, value) return if key in self._entries: self._entries[key].value = value return raise AttributeError(key) def __dir__(self): return list(super().__dir__()) + list(self._entries) @classmethod def parse(cls, f): entry_map = {} for entry in ENTRIES: entry_map[entry.name] = entry.copy() try: loaded = toml.load(f) for k, v in loaded.items(): if entry.type_ in data_constructors: v = data_constructors[entry.type_](k, v) if k not in entry_map: _l.warning( 'Unknown configuration option \'%s\'. Ignoring...', k) continue entry = entry_map[k] if type(v) is not entry.type_: _l.warning( 'Value \'%s\' for configuration option \'%s\' has type \'%s\', expected type \'%s\'. Ignoring...', v, k, type(v), entry.type_) continue entry.value = v except toml.TomlDecodeError as e: _l.error( 'Failed to parse configuration file: \'%s\'. Continuing with default options...', e.msg) return cls(entry_map)