def __init__(self, name=None, *, enable_meter=True, enable_transform=True, parent=None): super().__init__(parent=parent) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self._items = set() self._plot_items = set() self._plot_items2 = set() self._annotation_items = [] self._n_vis_annotation_items = 0 self._vb = pg.ViewBox(parent=self) self._vb2 = None if name is not None: self._vb.register(name) self._legend = None self._axes = {} self._meter = pg.LabelItem('', size='11pt', justify='left', color='6A3D9A', parent=self) self._title = pg.LabelItem('', size='11pt', parent=self) # context menu self._show_cross_cb = QCheckBox("Cross cursor") self._show_x_grid_cb = QCheckBox("Show X Grid") self._show_y_grid_cb = QCheckBox("Show Y Grid") self._grid_opacity_sld = QSlider(Qt.Horizontal) self._grid_opacity_sld.setMinimum(0) self._grid_opacity_sld.setMaximum(255) self._grid_opacity_sld.setValue(160) self._grid_opacity_sld.setSingleStep(1) self._log_x_cb = QCheckBox("Log X") self._log_y_cb = QCheckBox("Log Y") self._menu = None self._enable_transform = enable_transform self._enable_meter = enable_meter self._show_meter = False self._layout = QGraphicsGridLayout() self.initUI() self.initConnections()
def __init__(self, name, position, players, parent): super().__init__(parent=parent) self.name = name self.position = position self.tokens = [] self.owner = False self.layout = QGraphicsLinearLayout() self.token_layout = QGraphicsGridLayout() self.token_layout.setSpacing(0.5) self.name_on_tile = QGraphicsWidget() self.info = QGraphicsWidget() self.layout.setOrientation(Qt.Vertical) self.setContentsMargins(75, 0, 90, 0) property_name = QGraphicsTextItem(self.name, parent=self.name_on_tile) if name in parent.properties: self.real_pos = parent.board_positions[parent.properties.index(name)] if self.real_pos in mp_core.PROPERTIES: self.price = mp_core.PROPERTIES[self.real_pos][name]["Price"] self.rent = mp_core.PROPERTIES[self.real_pos][name]["Rent"] money_info = QGraphicsTextItem(f"Price: {self.price}", parent=self.info) elif self.real_pos in mp_core.SPECIAL_CASES: tile = list(mp_core.SPECIAL_CASES[self.real_pos].keys())[0] if tile == "Start": money_start = QGraphicsTextItem("Free monay: 200", parent=self.info) for player in players: token = Token(player) token.set_tile(tile) self.tokens.append(token) self.display_game_pieces() elif tile in ["Income Tax", "Super Tax"]: money = mp_core.SPECIAL_CASES[self.real_pos][tile] money_tax = QGraphicsTextItem(f"Tax: -{money}", parent=self.info) self.layout.addItem(self.name_on_tile) self.layout.addItem(self.info) self.layout.addItem(self.token_layout) self.setLayout(self.layout) self.layout.setAlignment(self.layout, Qt.AlignCenter)
def __init__(self, players): super().__init__() self.total_tokens = [] for player in players: self.total_tokens.append(Token(player)) self.board_layout = QGraphicsGridLayout() self.board_layout.setSpacing(0) self.properties = [ "Free Parking", "Strand", "Chance", "Fleet Street", "Trafalgar Square", "Fenchurch Street station", "Leicester Square", "Coventry Street", "Water Works", "Piccadilly", "Go to Jail", "Vine Street", "", "", "", "", "", "", "", "", "", "Regent Street", "Marlborough Street", "", "", "", "", "", "", "", "", "", "Oxford Street", "Community Chest", "", "", "", "", "", "", "", "", "", "Community Chest", "Bow Street", "", "", "", "", "", "", "", "", "", "Bond Street", "Marylebine station", "", "", "", "", "", "", "", "", "", "Liverpool Street station", "Northumberland Avenue", "", "", "", "", "", "", "", "", "", "Chance", "Whitehall", "", "", "", "", "", "", "", "", "", "Park Lane", "Electric Company", "", "", "", "", "", "", "", "", "", "Super Tax", "Pall Mall", "", "", "", "", "", "", "", "", "", "Mayfair", "Visit Jail", "Pentonville Road", "Euston Road", "Chance", "The Angel Islington", "King's Cross station", "Income Tax", "Whitechapel Road", "Community Chest", "Old Kent Road", "Start" ] self.board_positions = { 0: 20, 1: 21, 2: 22, 3: 23, 4: 24, 5: 25, 6: 26, 7: 27, 8: 28, 9: 29, 10: 30, 11: 19, 21: 31, 22: 18, 32: 32, 33: 17, 43: 33, 44: 16, 54: 34, 55: 15, 65: 35, 66: 14, 76: 36, 77: 13, 87: 37, 88: 12, 98: 38, 99: 11, 109: 39, 110: 10, 111: 9, 112: 8, 113: 7, 114: 6, 115: 5, 116: 4, 117: 3, 118: 2, 119: 1, 120: 0 } positions = [(i, j) for i in range(11) for j in range(11)] for position, name in zip(positions, self.properties): if name == "": continue self.board_layout.addItem(Tile(name, grid2pos(position), players, parent=self), *position) self.setLayout(self.board_layout)
def __init__(self, image=None, fillHistogram=True, bounds: tuple = None): GraphicsWidget.__init__(self) self.imageItem = lambda: None # fake a dead weakref self.layout = QGraphicsGridLayout() self.setLayout(self.layout) self.layout.setContentsMargins(1, 1, 1, 1) self.layout.setSpacing(0) self.vb = ViewBox(parent=self) # self.vb.setMaximumHeight(152) # self.vb.setMinimumWidth(45) self.vb.setMouseEnabled(x=True, y=False) self.region = LinearRegionItem([0, 1], 'vertical', swapMode='block', bounds=bounds) self.region.setZValue(1000) self.vb.addItem(self.region) self.region.lines[0].addMarker('<|', 0.5) self.region.lines[1].addMarker('|>', 0.5) self.region.sigRegionChanged.connect(self.regionChanging) self.region.sigRegionChangeFinished.connect(self.regionChanged) self.axis = AxisItem('bottom', linkView=self.vb, maxTickLength=-10, parent=self) self.layout.addItem(self.axis, 1, 0) self.layout.addItem(self.vb, 0, 0) self.range = None self.vb.sigRangeChanged.connect(self.viewRangeChanged) self.plot = PlotCurveItem(pen=(200, 200, 200, 100)) # self.plot.rotate(90) self.vb.addItem(self.plot) self.fillHistogram(fillHistogram) self._showRegions() self.autoHistogramRange() if image is not None: self.setImageItem(image)
def __init__(self, parent=None, direction=Qt.LeftToRight, node=None, icon=None, iconSize=None, **args): QGraphicsWidget.__init__(self, parent, **args) self.setAcceptedMouseButtons(Qt.NoButton) self.__direction = direction self.setLayout(QGraphicsLinearLayout(Qt.Horizontal)) # Set the maximum size, otherwise the layout can't grow beyond its # sizeHint (and we need it to grow so the widget can grow and keep the # contents centered vertically. self.layout().setMaximumSize(QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.__iconSize = iconSize or QSize(64, 64) self.__icon = icon self.__iconItem = QGraphicsPixmapItem(self) self.__iconLayoutItem = GraphicsItemLayoutItem(item=self.__iconItem) self.__channelLayout = QGraphicsGridLayout() self.__channelAnchors = [] if self.__direction == Qt.LeftToRight: self.layout().addItem(self.__iconLayoutItem) self.layout().addItem(self.__channelLayout) channel_alignemnt = Qt.AlignRight else: self.layout().addItem(self.__channelLayout) self.layout().addItem(self.__iconLayoutItem) channel_alignemnt = Qt.AlignLeft self.layout().setAlignment(self.__iconLayoutItem, Qt.AlignCenter) self.layout().setAlignment(self.__channelLayout, Qt.AlignVCenter | channel_alignemnt) if node is not None: self.setSchemeNode(node)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) width = Settings.NUM_BLOCKS_X * (Settings.WIDTH + 1) height = Settings.NUM_BLOCKS_Y * (Settings.HEIGHT + 1) self.setSceneRect(0, 0, height, width) self.setItemIndexMethod(QtWidgets.QGraphicsScene.NoIndex) layout = QGraphicsGridLayout() layout.setVerticalSpacing(0) layout.setHorizontalSpacing(0) form = QGraphicsWidget() form.setLayout(layout) for i in range(Settings.NUM_BLOCKS_X): layout.setRowSpacing(i, 0) layout.setRowMaximumHeight(i, Settings.HEIGHT) for j in range(Settings.NUM_BLOCKS_Y): layout.setColumnSpacing(j, 0) layout.setColumnMaximumWidth(j, Settings.WIDTH) if j - i == 1: rect = RectangleWidget(QRectF(0, 0, Settings.WIDTH, Settings.HEIGHT), path=True) elif j - i == 3: rect = RectangleWidget(QRectF(0, 0, Settings.WIDTH, Settings.HEIGHT), item=True) else: rect = RectangleWidget( QRectF(0, 0, Settings.WIDTH, Settings.HEIGHT)) layout.addItem(rect, i, j) self.addItem(form)
class Tile(QGraphicsWidget): def __init__(self, name, position, players, parent): super().__init__(parent=parent) self.name = name self.position = position self.tokens = [] self.owner = False self.layout = QGraphicsLinearLayout() self.token_layout = QGraphicsGridLayout() self.token_layout.setSpacing(0.5) self.name_on_tile = QGraphicsWidget() self.info = QGraphicsWidget() self.layout.setOrientation(Qt.Vertical) self.setContentsMargins(75, 0, 90, 0) property_name = QGraphicsTextItem(self.name, parent=self.name_on_tile) if name in parent.properties: self.real_pos = parent.board_positions[parent.properties.index(name)] if self.real_pos in mp_core.PROPERTIES: self.price = mp_core.PROPERTIES[self.real_pos][name]["Price"] self.rent = mp_core.PROPERTIES[self.real_pos][name]["Rent"] money_info = QGraphicsTextItem(f"Price: {self.price}", parent=self.info) elif self.real_pos in mp_core.SPECIAL_CASES: tile = list(mp_core.SPECIAL_CASES[self.real_pos].keys())[0] if tile == "Start": money_start = QGraphicsTextItem("Free monay: 200", parent=self.info) for player in players: token = Token(player) token.set_tile(tile) self.tokens.append(token) self.display_game_pieces() elif tile in ["Income Tax", "Super Tax"]: money = mp_core.SPECIAL_CASES[self.real_pos][tile] money_tax = QGraphicsTextItem(f"Tax: -{money}", parent=self.info) self.layout.addItem(self.name_on_tile) self.layout.addItem(self.info) self.layout.addItem(self.token_layout) self.setLayout(self.layout) self.layout.setAlignment(self.layout, Qt.AlignCenter) def is_owned(self): if self.owner: return True else: return False def set_owner(self, player): self.owner = player def get_owner(self): return self.owner def add_token(self, token): self.tokens.append(token) def remove_token(self, token): self.tokens.remove(token) def get_name(self): return self.name def get_pos(self): return self.position def display_game_pieces(self): if len(self.tokens) == 6 or len(self.tokens) == 5 or len(self.tokens) == 4: sub_layout = True sub_pos = 0 else: sub_layout = False for i, token in enumerate(self.tokens): if (len(self.tokens) == 4 and i >= 2) or ( len(self.tokens) >= 5 and i >= 3 ): if sub_layout: self.token_layout.addItem(token, 1, sub_pos) sub_pos += 1 else: self.token_layout.addItem(token, 0, i) return self.token_layout def paint(self, painter, option, widget): painter.drawRects(self.boundingRect()) def has_tokens(self): if self.tokens != []: return self.tokens else: return def get_token(self, player): for token in self.tokens: if player == token.get_player(): return token return def remove_token_layout(self, token): self.token_layout.removeItem(token)
def initUI(self): layout = QGraphicsGridLayout() layout.setContentsMargins(1, 1, 1, 1) layout.setSpacing(0) layout.addItem(self._axis, 0, 0) layout.addItem(self._vb, 0, 1) layout.addItem(self._gradient, 0, 2) self.setLayout(layout)
class PlotArea(pg.GraphicsWidget): """GraphicsWidget implementing a standard 2D plotting area with axes. Implemented based on pyqtgraph.PlotItem. It has the following functionalities: - Manage placement of a ViewBox, AxisItems, and LabelItems; - Manage a list of GraphicsItems displayed inside the ViewBox; - Implement a context menu with display options. """ cross_toggled_sgn = pyqtSignal(bool) _METER_ROW = 0 _TITLE_ROW = 1 _MAX_ANNOTATION_ITEMS = 10 def __init__(self, name=None, *, enable_meter=True, enable_transform=True, parent=None): super().__init__(parent=parent) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self._items = set() self._plot_items = set() self._plot_items2 = set() self._annotation_items = [] self._n_vis_annotation_items = 0 self._vb = pg.ViewBox(parent=self) self._vb2 = None if name is not None: self._vb.register(name) self._legend = None self._axes = {} self._meter = pg.LabelItem('', size='11pt', justify='left', color='6A3D9A', parent=self) self._title = pg.LabelItem('', size='11pt', parent=self) # context menu self._show_cross_cb = QCheckBox("Cross cursor") self._show_x_grid_cb = QCheckBox("Show X Grid") self._show_y_grid_cb = QCheckBox("Show Y Grid") self._grid_opacity_sld = QSlider(Qt.Horizontal) self._grid_opacity_sld.setMinimum(0) self._grid_opacity_sld.setMaximum(255) self._grid_opacity_sld.setValue(160) self._grid_opacity_sld.setSingleStep(1) self._log_x_cb = QCheckBox("Log X") self._log_y_cb = QCheckBox("Log Y") self._menu = None self._enable_transform = enable_transform self._enable_meter = enable_meter self._show_meter = False self._layout = QGraphicsGridLayout() self.initUI() self.initConnections() def initUI(self): layout = self._layout layout.setContentsMargins(1, 1, 1, 1) layout.setHorizontalSpacing(0) layout.setVerticalSpacing(0) layout.addItem(self._meter, self._METER_ROW, 1) layout.addItem(self._title, self._TITLE_ROW, 1) layout.addItem(self._vb, 3, 1) for i in range(5): layout.setRowPreferredHeight(i, 0) layout.setRowMinimumHeight(i, 0) layout.setRowSpacing(i, 0) layout.setRowStretchFactor(i, 1) for i in range(3): layout.setColumnPreferredWidth(i, 0) layout.setColumnMinimumWidth(i, 0) layout.setColumnSpacing(i, 0) layout.setColumnStretchFactor(i, 1) layout.setRowStretchFactor(2, 100) layout.setColumnStretchFactor(1, 100) self.setLayout(layout) self._initAxisItems() self.setTitle() self.showMeter(self._show_meter) self._initContextMenu() def initConnections(self): self._show_cross_cb.toggled.connect(self._onShowCrossChanged) self._show_x_grid_cb.toggled.connect(self._onShowGridChanged) self._show_y_grid_cb.toggled.connect(self._onShowGridChanged) self._grid_opacity_sld.sliderReleased.connect(self._onShowGridChanged) self._log_x_cb.toggled.connect(self._onLogXChanged) self._log_y_cb.toggled.connect(self._onLogYChanged) def _initContextMenu(self): self._menu = [QMenu("Meter"), QMenu("Grid"), QMenu("Transform")] meter_menu = self._menu[0] cross_act = QWidgetAction(meter_menu) cross_act.setDefaultWidget(self._show_cross_cb) meter_menu.addAction(cross_act) grid_menu = self._menu[1] show_x_act = QWidgetAction(grid_menu) show_x_act.setDefaultWidget(self._show_x_grid_cb) grid_menu.addAction(show_x_act) show_y_act = QWidgetAction(grid_menu) show_y_act.setDefaultWidget(self._show_y_grid_cb) grid_menu.addAction(show_y_act) opacity_act = QWidgetAction(grid_menu) widget = QWidget() layout = QHBoxLayout() layout.addWidget(QLabel("Opacity")) layout.addWidget(self._grid_opacity_sld) widget.setLayout(layout) opacity_act.setDefaultWidget(widget) grid_menu.addAction(opacity_act) transform_menu = self._menu[2] log_x_act = QWidgetAction(transform_menu) log_x_act.setDefaultWidget(self._log_x_cb) transform_menu.addAction(log_x_act) log_y_act = QWidgetAction(transform_menu) log_y_act.setDefaultWidget(self._log_y_cb) transform_menu.addAction(log_y_act) def _initAxisItems(self): for orient, pos in (('top', (2, 1)), ('bottom', (4, 1)), ('left', (3, 0)), ('right', (3, 2))): axis = pg.AxisItem(orientation=orient, parent=self) axis.linkToView(self._vb) self._axes[orient] = {'item': axis, 'pos': pos} self._layout.addItem(axis, *pos) axis.setZValue(-1000) axis.setFlag(axis.ItemNegativeZStacksBehindParent) self.showAxis(orient, orient in ['left', 'bottom']) def getViewBox(self): return self._vb def clearAllPlotItems(self): """Clear data on all the plot items.""" for item in chain(self._plot_items, self._plot_items2): item.setData([], []) @pyqtSlot(bool) def _onShowCrossChanged(self, state): self.showMeter(state) self.cross_toggled_sgn.emit(state) @pyqtSlot() def _onShowGridChanged(self): alpha = self._grid_opacity_sld.value() x = alpha if self._show_x_grid_cb.isChecked() else False y = alpha if self._show_y_grid_cb.isChecked() else False self.getAxis('bottom').setGrid(x) self.getAxis('left').setGrid(y) @pyqtSlot(bool) def _onLogXChanged(self, state): for item in chain(self._plot_items, self._plot_items2): item.setLogX(state) self.getAxis("bottom").setLogMode(state) self._vb.autoRange(disableAutoRange=False) @pyqtSlot(bool) def _onLogYChanged(self, state): for item in self._plot_items: item.setLogY(state) self.getAxis("left").setLogMode(state) self._vb.autoRange(disableAutoRange=False) def addItem(self, item, ignore_bounds=False, y2=False): """Add a graphics item to ViewBox.""" if item in self._items: warnings.warn(f'Item {item} already added to PlotItem, ignoring.') return self._items.add(item) if isinstance(item, pg.PlotItem): if y2: if self._log_x_cb.isChecked(): item.setLogX(True) self._plot_items2.add(item) else: if self._log_x_cb.isChecked(): item.setLogX(True) if self._log_y_cb.isChecked(): item.setLogY(True) self._plot_items.add(item) name = item.name() if self._legend is not None and name: self._legend.addItem(item, name) if y2: vb = self._vb2 if vb is None: vb = pg.ViewBox() self.scene().addItem(vb) right_axis = self.getAxis('right') right_axis.linkToView(vb) right_axis.show() vb.setXLink(self._vb) self._vb2 = vb self._vb.sigResized.connect(self._updateY2View) else: vb = self._vb vb.addItem(item, ignoreBounds=ignore_bounds) def _updateY2View(self): self._vb2.setGeometry(self._vb.sceneBoundingRect()) # not sure this is required # vb.linkedViewChanged(self._plot_area.vb, vb.XAxis) def removeItem(self, item): """Add a graphics item to ViewBox.""" if item not in self._items: return if item in self._annotation_items: # it is tricky to update n_vis_annotation_items raise RuntimeError("Annotation item is not allowed to be removed " "using 'removeItem' method!") self._items.remove(item) if item in self._plot_items2: self._plot_items2.remove(item) if self._legend is not None and item.name(): self._legend.removeItem(item) self._vb2.removeItem(item) return if item in self._plot_items: self._plot_items.remove(item) if self._legend is not None and item.name(): self._legend.removeItem(item) self._vb.removeItem(item) def removeAllItems(self): """Remove all graphics items from the ViewBox.""" for item in self._items: if item in self._plot_items2: self._vb2.removeItem(item) else: self._vb.removeItem(item) if self._legend is not None: self._legend.clear() self._plot_items.clear() self._plot_items2.clear() self._annotation_items.clear() self._n_vis_annotation_items = 0 self._items.clear() def getContextMenus(self, event): """Override.""" start = 0 end = len(self._menu) if not self._enable_transform: end -= 1 if not self._enable_meter: start += 1 return self._menu[start:end] def getAxis(self, axis): """Return the specified AxisItem. :param str axis: one of 'left', 'bottom', 'right', or 'top'. """ return self._axes[axis]['item'] def showAxis(self, axis, show=True): """Show or hide the given axis. :param str axis: one of 'left', 'bottom', 'right', or 'top'. :param bool show: whether to show the axis. """ s = self.getAxis(axis) if show: s.show() else: s.hide() def addLegend(self, offset=(30, 30), **kwargs): """Add a LegendItem if it does not exist.""" if self._legend is None: self._legend = pg.LegendItem(offset=offset, pen='k', **kwargs) self._legend.setParentItem(self._vb) for item in chain(self._plot_items, self._plot_items2): name = item.name() if name: self._legend.addItem(item, name) return self._legend def showLegend(self, show=True): """Show or hide the legend. :param bool show: whether to show the legend. """ if show: self._legend.show() else: self._legend.hide() def setLabel(self, axis, text=None, units=None, **args): """Set the label for an axis. Basic HTML formatting is allowed. :param str axis: one of 'left', 'bottom', 'right', or 'top'. :param str text: text to display along the axis. HTML allowed. """ self.getAxis(axis).setLabel(text=text, units=units, **args) self.showAxis(axis) def showLabel(self, axis, show=True): """Show or hide one of the axis labels. :param str axis: one of 'left', 'bottom', 'right', or 'top'. :param bool show: whether to show the label. """ self.getAxis(axis).showLabel(show) def showMeter(self, show=True): """Show or hide the meter bar. :param bool show: whether to show the meter bar. """ row = self._METER_ROW if not show: self._meter.setMaximumHeight(0) self._layout.setRowFixedHeight(row, 0) self._meter.setVisible(False) else: self._meter.setMaximumHeight(30) self._layout.setRowFixedHeight(row, 30) self._meter.setVisible(True) self._show_meter = show def setMeter(self, pos): """Set the meter of the plot.""" if not self._show_meter: return if pos is None: self._meter.setText("") else: x, y = pos self._meter.setText(f"x = {x}, y = {y}") def setAnnotationList(self, x, y, values=None): """Set a list of annotation items. :param list-like x: x coordinate of the annotated point. :param list-like y: y coordinate of the annotated point. :param list-like values: a list of annotation text. """ # Don't waste time to check the list lengths. a_items = self._annotation_items if values is None: values = x values = values[:self._MAX_ANNOTATION_ITEMS] n_pts = len(values) n_items = len(a_items) if n_items < n_pts: for i in range(n_pts - n_items): item = pg.TextItem(color=FColor.mkColor('b'), anchor=(0.5, 2)) self.addItem(item) a_items.append(item) n_vis = self._n_vis_annotation_items if n_vis < n_pts: for i in range(n_vis, n_pts): a_items[i].show() elif n_vis > n_pts: for i in range(n_pts, n_vis): a_items[i].hide() self._n_vis_annotation_items = n_pts for i in range(n_pts): a_items[i].setPos(x[i], y[i]) a_items[i].setText(f"{values[i]:.4f}") def setTitle(self, *args, **kwargs): """Set the title of the plot.""" row = self._TITLE_ROW title = None if len(args) == 0 else args[0] if title is None: self._title.setMaximumHeight(0) self._layout.setRowFixedHeight(row, 0) self._title.setVisible(False) else: self._title.setMaximumHeight(30) self._layout.setRowFixedHeight(row, 30) self._title.setText(title, **kwargs) self._title.setVisible(True) def setAspectLocked(self, *args, **kwargs): self._vb.setAspectLocked(*args, **kwargs) def invertX(self, *args, **kwargs): self._vb.invertX(*args, **kwargs) def invertY(self, *args, **kwargs): self._vb.invertY(*args, **kwargs) def autoRange(self, *args, **kwargs): self._vb.autoRange(*args, **kwargs) def mapSceneToView(self, *args, **kwargs): return self._vb.mapSceneToView(*args, **kwargs)
def __init__(self, dither, detectors, *args): super().__init__(*args) self._enabled_detectors = detectors self._boxes = { } # this will be of the form {detector_number: DetectorBox} self.gv_layout = QGraphicsGridLayout() self.gv_layout.setSpacing(0) min_length = DetectorBox.length * 4 + 6 self._min_length = min_length self._dither = dither self.gv_layout.setMinimumSize(min_length, min_length) self.gv_layout.setMaximumSize(min_length, min_length) self.gv_layout.setContentsMargins(0, 0, 0, 0) self.setMinimumWidth(min_length) self.setMinimumHeight(min_length) self.setMaximumWidth(min_length + 20) self.setMaximumHeight(min_length + 20) self._init_boxes() gv_widget = QGraphicsWidget() gv_widget.setLayout(self.gv_layout) gv_widget.setContentsMargins(0, 0, 0, 0) scene = QGraphicsScene() scene.addItem(gv_widget) scene.setSceneRect(0, 0, min_length, min_length) view = QGraphicsView() view.setMouseTracking(True) view.setViewportMargins(0, 0, 0, 0) view.setGeometry(0, 0, min_length, min_length) view.setStyleSheet("border: 0px; margin: 0px; padding: 0px;") view.setScene(scene) view.setTransform(flip_vertical, True) layout = QVBoxLayout() layout.addWidget(view) self.setLayout(layout)
class MultiDetectorSelector(QWidget): """ Constructs a detector selector consisting of 4 x 4 squares, numbered to be consistent with the SIR numbering scheme. This allows the user to specify which detectors they are interested in viewing / inspecting. """ updated = pyqtSignal() def __init__(self, dither, detectors, *args): super().__init__(*args) self._enabled_detectors = detectors self._boxes = { } # this will be of the form {detector_number: DetectorBox} self.gv_layout = QGraphicsGridLayout() self.gv_layout.setSpacing(0) min_length = DetectorBox.length * 4 + 6 self._min_length = min_length self._dither = dither self.gv_layout.setMinimumSize(min_length, min_length) self.gv_layout.setMaximumSize(min_length, min_length) self.gv_layout.setContentsMargins(0, 0, 0, 0) self.setMinimumWidth(min_length) self.setMinimumHeight(min_length) self.setMaximumWidth(min_length + 20) self.setMaximumHeight(min_length + 20) self._init_boxes() gv_widget = QGraphicsWidget() gv_widget.setLayout(self.gv_layout) gv_widget.setContentsMargins(0, 0, 0, 0) scene = QGraphicsScene() scene.addItem(gv_widget) scene.setSceneRect(0, 0, min_length, min_length) view = QGraphicsView() view.setMouseTracking(True) view.setViewportMargins(0, 0, 0, 0) view.setGeometry(0, 0, min_length, min_length) view.setStyleSheet("border: 0px; margin: 0px; padding: 0px;") view.setScene(scene) view.setTransform(flip_vertical, True) layout = QVBoxLayout() layout.addWidget(view) self.setLayout(layout) @property def dither_number(self): return self._dither @property def min_length(self): return self._min_length def _init_boxes(self): for row in range(4): for column in range(4): detector_id = box_id(row, column) enabled = detector_id in self._enabled_detectors box = DetectorBox(row, column, enabled) box.set_parent_selector(self) self._boxes[detector_id] = box box_layout = DetectorBoxLayout(box) self.gv_layout.addItem(box_layout, row, column) self.gv_layout.setRowAlignment(row, Qt.AlignCenter) self.gv_layout.setColumnAlignment(column, Qt.AlignCenter) def selected_detectors(self): ''' Returns a list of IDs of the selected boxes. If there are no selected boxes, then None is returned ''' selected = [ box.detector_id for box in self._boxes.values() if box.selected ] return selected if len(selected) > 0 else None def selection_changed(self): self.updated.emit()
class HistogramItem(GraphicsWidget): """ This is a graphicsWidget which provides controls for adjusting the display of an image. Includes: - Image histogram - Movable region over histogram to select black/white levels Parameters ---------- image : ImageItem or None If *image* is provided, then the control will be automatically linked to the image and changes to the control will be immediately reflected in the image's appearance. fillHistogram : bool By default, the histogram is rendered with a fill. For performance, set *fillHistogram* = False. """ sigLevelsChanged = pyqtSignal(object) sigLevelChangeFinished = pyqtSignal(object) def __init__(self, image=None, fillHistogram=True, bounds: tuple = None): GraphicsWidget.__init__(self) self.imageItem = lambda: None # fake a dead weakref self.layout = QGraphicsGridLayout() self.setLayout(self.layout) self.layout.setContentsMargins(1, 1, 1, 1) self.layout.setSpacing(0) self.vb = ViewBox(parent=self) # self.vb.setMaximumHeight(152) # self.vb.setMinimumWidth(45) self.vb.setMouseEnabled(x=True, y=False) self.region = LinearRegionItem([0, 1], 'vertical', swapMode='block', bounds=bounds) self.region.setZValue(1000) self.vb.addItem(self.region) self.region.lines[0].addMarker('<|', 0.5) self.region.lines[1].addMarker('|>', 0.5) self.region.sigRegionChanged.connect(self.regionChanging) self.region.sigRegionChangeFinished.connect(self.regionChanged) self.axis = AxisItem('bottom', linkView=self.vb, maxTickLength=-10, parent=self) self.layout.addItem(self.axis, 1, 0) self.layout.addItem(self.vb, 0, 0) self.range = None self.vb.sigRangeChanged.connect(self.viewRangeChanged) self.plot = PlotCurveItem(pen=(200, 200, 200, 100)) # self.plot.rotate(90) self.vb.addItem(self.plot) self.fillHistogram(fillHistogram) self._showRegions() self.autoHistogramRange() if image is not None: self.setImageItem(image) def fillHistogram(self, fill=True, level=0.0, color=(100, 100, 200)): if fill: self.plot.setFillLevel(level) self.plot.setBrush(color) else: self.plot.setFillLevel(None) def paint(self, p, *args): rgn = self.getLevels() self.vb.mapFromViewToItem(self, Point(self.vb.viewRect().center().x(), rgn[0])) self.vb.mapFromViewToItem(self, Point(self.vb.viewRect().center().x(), rgn[1])) def setHistogramRange(self, mn, mx, padding=0.1): """Set the Y range on the histogram plot. This disables auto-scaling.""" self.vb.enableAutoRange(self.vb.XAxis, False) self.vb.setYRange(mn, mx, padding) def autoHistogramRange(self): """Enable auto-scaling on the histogram plot.""" self.vb.enableAutoRange(self.vb.XYAxes) def setImageItem(self, img): """Set an ImageItem to have its levels and LUT automatically controlled by this HistogramLUTItem. """ self.imageItem = weakref.ref(img) img.sigImageChanged.connect(self.imageChanged) self.regionChanged() self.imageChanged(autoLevel=True) def viewRangeChanged(self): self.update() def regionChanged(self): if self.imageItem() is not None: self.imageItem().setLevels(self.getLevels()) self.sigLevelChangeFinished.emit(self) def regionChanging(self): if self.imageItem() is not None: self.imageItem().setLevels(self.getLevels()) self.sigLevelsChanged.emit(self) self.update() def imageChanged(self, autoLevel=False): if self.imageItem() is None: return self.plot.setVisible(True) # plot one histogram for all image data h = self.imageItem().getHistogram() if h[0] is None: return self.plot.setData(*h) if autoLevel: mn = h[0][0] mx = h[0][-1] self.region.setRegion([mn, mx]) else: mn, mx = self.imageItem().levels self.region.setRegion([mn, mx]) def getLevels(self): """ Return the min and max levels. """ return self.region.getRegion() def setLevels(self, min=None, max=None): """ Set the min/max (bright and dark) levels. """ assert None not in (min, max) self.region.setRegion((min, max)) def _showRegions(self): self.region.setVisible(True) def saveState(self): return { 'levels': self.getLevels(), } def restoreState(self, state): self.setLevels(*state['levels'])
def __updateState(self): """ Update the widget with the new source/sink node signal descriptions. """ widget = QGraphicsWidget() widget.setLayout(QGraphicsGridLayout()) # Space between left and right anchors widget.layout().setHorizontalSpacing(50) left_node = EditLinksNode(self, direction=Qt.LeftToRight, node=self.source) left_node.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) right_node = EditLinksNode(self, direction=Qt.RightToLeft, node=self.sink) right_node.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) left_node.setMinimumWidth(150) right_node.setMinimumWidth(150) widget.layout().addItem( left_node, 0, 0, ) widget.layout().addItem( right_node, 0, 1, ) title_template = "<center><b>{0}<b></center>" left_title = GraphicsTextWidget(self) left_title.setHtml(title_template.format(escape(self.source.title))) left_title.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) right_title = GraphicsTextWidget(self) right_title.setHtml(title_template.format(escape(self.sink.title))) right_title.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) widget.layout().addItem(left_title, 1, 0, alignment=Qt.AlignHCenter | Qt.AlignTop) widget.layout().addItem(right_title, 1, 1, alignment=Qt.AlignHCenter | Qt.AlignTop) widget.setParentItem(self) max_w = max( left_node.sizeHint(Qt.PreferredSize).width(), right_node.sizeHint(Qt.PreferredSize).width()) # fix same size left_node.setMinimumWidth(max_w) right_node.setMinimumWidth(max_w) left_title.setMinimumWidth(max_w) right_title.setMinimumWidth(max_w) self.layout().addItem(widget) self.layout().activate() self.sourceNodeWidget = left_node self.sinkNodeWidget = right_node self.sourceNodeTitle = left_title self.sinkNodeTitle = right_title
def __init__( self, name, board_pos, price, rent, mortgage, players, color, group_name, number_in_group, house_price, parent, ): super().__init__(parent=parent) self.name = name self.board_pos = board_pos self.price = price self.rent = rent self.mortgage = mortgage self.color = color self.group_name = group_name self.number_in_group = number_in_group self.tokens = [] self.owner = False self.house_price = house_price self.nb_houses = 0 self.hotel = False self.layout = QGraphicsLinearLayout() self.token_layout = QGraphicsGridLayout() self.color_property = QGraphicsWidget() self.name_on_tile = QGraphicsWidget() self.info = QGraphicsWidget() self.layout.setOrientation(Qt.Vertical) property_name = QGraphicsTextItem(self.name, parent=self.name_on_tile) if name in parent.properties: if self.board_pos in core.PROPERTIES: money_info = QGraphicsTextItem(f"Price: {self.price}", parent=self.info) self.color_rect = self.color_tile(color) elif self.board_pos in core.SPECIAL_CASES: if name == "Start": money_start = QGraphicsTextItem( f"Free monay: {self.price}", parent=self.info) for player, color in players.items(): token = Token.Token(player, color) token.set_tile(self) self.tokens.append(token) self.display_game_pieces() elif name in ["Income Tax", "Super Tax"]: money_tax = QGraphicsTextItem(f"Tax: -{self.price}", parent=self.info) self.token_layout.setColumnMaximumWidth(0, 22) self.token_layout.setColumnMaximumWidth(1, 22) self.token_layout.setColumnMaximumWidth(2, 22) self.token_layout.setSpacing(1) self.layout.addItem(self.color_property) self.layout.addItem(self.name_on_tile) self.layout.addItem(self.info) self.layout.addItem(self.token_layout) self.setLayout(self.layout) self.setContentsMargins(0, 0, 100, 0)
class Tile(QGraphicsWidget): """ Tile class """ def __init__( self, name, board_pos, price, rent, mortgage, players, color, group_name, number_in_group, house_price, parent, ): super().__init__(parent=parent) self.name = name self.board_pos = board_pos self.price = price self.rent = rent self.mortgage = mortgage self.color = color self.group_name = group_name self.number_in_group = number_in_group self.tokens = [] self.owner = False self.house_price = house_price self.nb_houses = 0 self.hotel = False self.layout = QGraphicsLinearLayout() self.token_layout = QGraphicsGridLayout() self.color_property = QGraphicsWidget() self.name_on_tile = QGraphicsWidget() self.info = QGraphicsWidget() self.layout.setOrientation(Qt.Vertical) property_name = QGraphicsTextItem(self.name, parent=self.name_on_tile) if name in parent.properties: if self.board_pos in core.PROPERTIES: money_info = QGraphicsTextItem(f"Price: {self.price}", parent=self.info) self.color_rect = self.color_tile(color) elif self.board_pos in core.SPECIAL_CASES: if name == "Start": money_start = QGraphicsTextItem( f"Free monay: {self.price}", parent=self.info) for player, color in players.items(): token = Token.Token(player, color) token.set_tile(self) self.tokens.append(token) self.display_game_pieces() elif name in ["Income Tax", "Super Tax"]: money_tax = QGraphicsTextItem(f"Tax: -{self.price}", parent=self.info) self.token_layout.setColumnMaximumWidth(0, 22) self.token_layout.setColumnMaximumWidth(1, 22) self.token_layout.setColumnMaximumWidth(2, 22) self.token_layout.setSpacing(1) self.layout.addItem(self.color_property) self.layout.addItem(self.name_on_tile) self.layout.addItem(self.info) self.layout.addItem(self.token_layout) self.setLayout(self.layout) self.setContentsMargins(0, 0, 100, 0) def is_owned(self): if self.owner: return True else: return False def set_owner(self, player): self.owner = player def get_owner(self): return self.owner def remove_owner(self): self.owner = False def add_token(self, token): self.tokens.append(token) def remove_token(self, token): self.tokens.remove(token) def remove_token_layout(self, token): self.token_layout.removeItem(token) def add_houses(self, number): self.nb_houses += number self.display_houses() def add_hotel(self): self.nb_houses = 0 self.hotel = True self.display_hotel() def get_name(self): return self.name def get_board_pos(self): return self.board_pos def get_token(self, player): for token in self.tokens: if player == token.get_player(): return token return def get_all_tokens(self): return self.tokens def get_price(self): return self.price def get_rent(self): if self.hotel: return self.rent * self.parent().hotel_multiplier elif self.nb_houses: return self.rent * self.parent().house2mutliplier[self.nb_houses] else: return self.rent def get_mortgage(self): return self.mortgage def get_color(self): return self.color def get_group(self): return self.group_name def get_nb_houses(self): return self.nb_houses def get_house_price(self): return self.house_price def get_number_in_group(self): return self.number_in_group def has_tokens(self): if self.tokens != []: return True else: return False def display_game_pieces(self): """ Display the tokens on the tile according to their number i.e. if there's 4, i want a 2x2 grid if there's 5 or more, i want a 3xn grid """ if len(self.tokens) >= 4: sub_layout = True sub_pos = 0 else: sub_layout = False for i, token in enumerate(self.tokens): if (len(self.tokens) == 4 and i >= 2) or (len(self.tokens) >= 5 and i >= 3): if sub_layout: self.token_layout.addItem(token, 1, sub_pos) sub_pos += 1 else: self.token_layout.addItem(token, 0, i) def display_houses(self): for i in range(self.nb_houses): width, height = self.color_rect.boundingRect().getRect()[2:] set_color = QColor() set_color.setNamedColor("#00FF00") house = QGraphicsRectItem(width / 4 * i + 5, height / 4, width / 4 - 10, height / 2) house.setParentItem(self.color_rect) house.setBrush(QBrush(set_color, style=Qt.Dense1Pattern)) def display_hotel(self): if self.hotel: width, height = self.color_rect.boundingRect().getRect()[2:] houses = self.color_rect.childItems() for house in houses: house.setParentItem(None) rect_color = QColor() rect_color.setNamedColor("#FF0000") pen_color = QColor() pen_color.setNamedColor("#00A500") pen = QPen() pen.setBrush(QBrush(pen_color)) pen.setWidth(2) hotel = QGraphicsRectItem(width / 4, height / 4, width / 2, height / 2) hotel.setParentItem(self.color_rect) hotel.setBrush(QBrush(rect_color, style=Qt.Dense1Pattern)) hotel.setPen(pen) def paint(self, painter, option, widget): painter.drawRects(self.boundingRect()) def color_tile(self, color): set_color = QColor() set_color.setNamedColor(color) color_rect = QGraphicsRectItem(0, 0, 150, 25, parent=self.color_property) color_rect.setBrush(QBrush(set_color, style=Qt.SolidPattern)) return color_rect