diff --git a/zxlive/commands.py b/zxlive/commands.py index 3c69590a..68659712 100644 --- a/zxlive/commands.py +++ b/zxlive/commands.py @@ -14,7 +14,8 @@ from pyzx.symbolic import Poly from pyzx.utils import EdgeType, VertexType, get_w_partner, vertex_is_w, get_w_io, get_z_box_label, set_z_box_label -from .common import ET, VT, W_INPUT_OFFSET, GraphT, setting +from .common import ET, VT, W_INPUT_OFFSET, GraphT +from .settings import display_setting from .eitem import EItem from .graphview import GraphView from .proof import ProofModel, ProofStepView, Rewrite @@ -202,8 +203,8 @@ def undo(self) -> None: self.update_graph_view() def redo(self) -> None: - y = round(self.y * setting.SNAP_DIVISION) / setting.SNAP_DIVISION - x = round(self.x * setting.SNAP_DIVISION) / setting.SNAP_DIVISION + y = round(self.y * display_setting.SNAP_DIVISION) / display_setting.SNAP_DIVISION + x = round(self.x * display_setting.SNAP_DIVISION) / display_setting.SNAP_DIVISION self._added_vert = self.g.add_vertex(self.vty, y,x) self.update_graph_view() @@ -224,8 +225,8 @@ def undo(self) -> None: self.update_graph_view() def redo(self) -> None: - y = round(self.y * setting.SNAP_DIVISION) / setting.SNAP_DIVISION - x = round(self.x * setting.SNAP_DIVISION) / setting.SNAP_DIVISION + y = round(self.y * display_setting.SNAP_DIVISION) / display_setting.SNAP_DIVISION + x = round(self.x * display_setting.SNAP_DIVISION) / display_setting.SNAP_DIVISION self._added_input_vert = self.g.add_vertex(VertexType.W_INPUT, y - W_INPUT_OFFSET, self.x) self._added_output_vert = self.g.add_vertex(VertexType.W_OUTPUT, y, x) self.g.add_edge((self._added_input_vert, self._added_output_vert), EdgeType.W_IO) diff --git a/zxlive/common.py b/zxlive/common.py index beb0ff43..2dc8fedf 100644 --- a/zxlive/common.py +++ b/zxlive/common.py @@ -1,22 +1,34 @@ +from __future__ import annotations + import os from enum import IntEnum -from typing import Final, Dict, Any, Optional +from typing import Final, Optional, TypeVar, Type from pyzx import EdgeType from typing_extensions import TypeAlias from PySide6.QtCore import QSettings -from PySide6.QtGui import QColor -from PySide6.QtWidgets import QTabWidget import pyzx _ROOT = os.path.abspath(os.path.dirname(__file__)) +T = TypeVar('T') + + def get_data(path: str) -> str: return os.path.join(os.environ.get("_MEIPASS", _ROOT), path) + +def get_settings_value(arg: str, _type: Type[T], default: T | None = None, settings: QSettings | None = None) -> T: + _settings = settings or QSettings("zxlive", "zxlive") + if not isinstance(val := _settings.value(arg, default), _type): + if default is not None: + return default + raise ValueError(f"Unexpected type for {val}: expected {_type}, got {type(val)}") + return val + def get_custom_rules_path() -> str: settings = QSettings("zxlive", "zxlive") return str(settings.value('path/custom-rules')) @@ -25,6 +37,7 @@ def get_custom_rules_path() -> str: VT: TypeAlias = int ET: TypeAlias = tuple[int, int, EdgeType] GraphT: TypeAlias = pyzx.graph.multigraph.Multigraph + def new_graph() -> GraphT: g = GraphT() g.set_auto_simplify(False) @@ -37,86 +50,6 @@ class ToolType(IntEnum): SCALE: Final = 64.0 - -defaults: Dict[str,Any] = { - "path/custom-rules": "lemmas/", - "color-scheme": "modern-red-green", - "tab-bar-location": QTabWidget.TabPosition.North, - "snap-granularity": '4', - "input-circuit-format": 'openqasm', - - "tikz/boundary-export": pyzx.settings.tikz_classes['boundary'], - "tikz/Z-spider-export": pyzx.settings.tikz_classes['Z'], - "tikz/X-spider-export": pyzx.settings.tikz_classes['X'], - "tikz/Z-phase-export": pyzx.settings.tikz_classes['Z phase'], - "tikz/X-phase-export": pyzx.settings.tikz_classes['X phase'], - "tikz/z-box-export": pyzx.settings.tikz_classes['Z box'], - "tikz/Hadamard-export": pyzx.settings.tikz_classes['H'], - "tikz/w-output-export": pyzx.settings.tikz_classes['W'], - "tikz/w-input-export": pyzx.settings.tikz_classes['W input'], - "tikz/edge-export": pyzx.settings.tikz_classes['edge'], - "tikz/edge-H-export": pyzx.settings.tikz_classes['H-edge'], - "tikz/edge-W-export": pyzx.settings.tikz_classes['W-io-edge'], - - "tikz/boundary-import": ", ".join(pyzx.tikz.synonyms_boundary), - "tikz/Z-spider-import": ", ".join(pyzx.tikz.synonyms_z), - "tikz/X-spider-import": ", ".join(pyzx.tikz.synonyms_x), - "tikz/Hadamard-import": ", ".join(pyzx.tikz.synonyms_hadamard), - "tikz/w-input-import": ", ".join(pyzx.tikz.synonyms_w_input), - "tikz/w-output-import": ", ".join(pyzx.tikz.synonyms_w_output), - "tikz/z-box-import": ", ".join(pyzx.tikz.synonyms_z_box), - "tikz/edge-import": ", ".join(pyzx.tikz.synonyms_edge), - "tikz/edge-H-import": ", ".join(pyzx.tikz.synonyms_hedge), - "tikz/edge-W-import": ", ".join(pyzx.tikz.synonyms_wedge), - - "tikz/layout/hspace": 2.0, - "tikz/layout/vspace": 2.0, - "tikz/layout/max-width": 10.0, - - "tikz/names/fuse spiders": "f", - "tikz/names/bialgebra": "b", - "tikz/names/change color to Z": "cc", - "tikz/names/change color to X": "cc", - "tikz/names/remove identity": "id", - "tikz/names/Add Z identity": "id", - "tikz/names/copy 0/pi spider": "cp", - "tikz/names/push Pauli": "pi", - "tikz/names/decompose hadamard": "eu", -} - -color_schemes = { - 'modern-red-green': "Modern Red & Green", - 'classic-red-green': "Classic Red & Green", - 'white-grey': "Dodo book White & Grey", - 'gidney': "Gidney's Black & White", -} - -input_circuit_formats = { - 'openqasm': "standard OpenQASM", - 'sqasm': "Spider QASM", - 'sqasm-no-simplification': "Spider QASM (no simplification)", -} - -# Initialise settings -settings = QSettings("zxlive", "zxlive") -for key, value in defaults.items(): - if not settings.contains(key): - settings.setValue(key, value) - - -class Settings(object): - SNAP_DIVISION = 4 # Should be an integer dividing SCALE - - def __init__(self) -> None: - self.update() - - def update(self) -> None: - settings = QSettings("zxlive", "zxlive") - self.SNAP_DIVISION = int(settings.value("snap-granularity")) - self.SNAP = SCALE / self.SNAP_DIVISION - -setting = Settings() - # Offsets should be a multiple of SCALE for grid snapping to work properly OFFSET_X: Final = 300 * SCALE OFFSET_Y: Final = 300 * SCALE @@ -144,107 +77,6 @@ def pos_from_view_int(x:float,y: float) -> tuple[int, int]: def view_to_length(width:float,height:float)-> tuple[float, float]: return (width / SCALE, height / SCALE) - -class Colors(object): - z_spider: QColor = QColor("#ccffcc") - z_spider_pressed: QColor = QColor("#64BC90") - x_spider: QColor = QColor("#ff8888") - x_spider_pressed: QColor = QColor("#bb0f0f") - hadamard: QColor = QColor("#ffff00") - hadamard_pressed: QColor = QColor("#f1c232") - boundary: QColor = QColor("#000000") - boundary_pressed: QColor = QColor("#444444") - w_input: QColor = QColor("#000000") - w_input_pressed: QColor = QColor("#444444") - w_output: QColor = QColor("#000000") - w_output_pressed: QColor = QColor("#444444") - outline: QColor = QColor("#000000") - - def __init__(self, color_scheme:str): - self.set_color_scheme(color_scheme) - - def set_color_scheme(self, color_scheme: str) -> None: - if color_scheme == 'modern-red-green': - self.z_spider = QColor("#ccffcc") - self.z_spider_pressed = QColor("#64BC90") - self.x_spider = QColor("#ff8888") - self.x_spider_pressed = QColor("#bb0f0f") - self.hadamard = QColor("#ffff00") - self.hadamard_pressed = QColor("#f1c232") - self.boundary = QColor("#000000") - elif color_scheme == 'classic-red-green': - self.z_spider = QColor("#00ff00") - self.z_spider_pressed = QColor("#00dd00") - self.x_spider = QColor("#ff0d00") - self.x_spider_pressed = QColor("#dd0b00") - self.hadamard = QColor("#ffff00") - self.hadamard_pressed = QColor("#f1c232") - self.boundary = QColor("#000000") - elif color_scheme == 'white-grey': - self.z_spider = QColor("#ffffff") - self.z_spider_pressed = QColor("#eeeeee") - self.x_spider = QColor("#b4b4b4") - self.x_spider_pressed = QColor("#a0a0a0") - self.hadamard = QColor("#ffffff") - self.hadamard_pressed = QColor("#dddddd") - self.boundary = QColor("#000000") - elif color_scheme == 'gidney': - self.z_spider = QColor("#000000") - self.z_spider_pressed = QColor("#222222") - self.x_spider = QColor("#ffffff") - self.x_spider_pressed = QColor("#dddddd") - self.hadamard = QColor("#ffffff") - self.hadamard_pressed = QColor("#dddddd") - self.boundary = QColor("#000000") - else: - raise ValueError(f"Unknown colour scheme {color_scheme}") - - -settings = QSettings("zxlive", "zxlive") -color_scheme = settings.value("color-scheme") -if color_scheme is None: color_scheme = str(defaults["color-scheme"]) -else: color_scheme = str(color_scheme) -colors = Colors(color_scheme) - - -def set_pyzx_tikz_settings() -> None: - tikz_classes = { - 'boundary': str(settings.value('tikz/boundary-export') or pyzx.settings.tikz_classes['boundary']), - 'Z': str(settings.value('tikz/Z-spider-export') or pyzx.settings.tikz_classes['Z']), - 'X': str(settings.value('tikz/X-spider-export') or pyzx.settings.tikz_classes['X']), - 'Z phase': str(settings.value('tikz/Z-phase-export') or pyzx.settings.tikz_classes['Z phase']), - 'X phase': str(settings.value('tikz/X-phase-export') or pyzx.settings.tikz_classes['X phase']), - 'Z box': str(settings.value('tikz/Z-box-export') or pyzx.settings.tikz_classes['Z box']), - 'H': str(settings.value('tikz/Hadamard-export') or pyzx.settings.tikz_classes['H']), - 'W': str(settings.value('tikz/W-output-export') or pyzx.settings.tikz_classes['W']), - 'W input': str(settings.value('tikz/W-input-export') or pyzx.settings.tikz_classes['W input']), - 'edge': str(settings.value('tikz/edge-export') or pyzx.settings.tikz_classes['edge']), - 'H-edge': str(settings.value('tikz/edge-H-export') or pyzx.settings.tikz_classes['H-edge']), - 'W-io-edge': str(settings.value('tikz/edge-W-export') or pyzx.settings.tikz_classes['W-io-edge']), - } - - def _get_synonyms(key: str, default: list[str]) -> list[str]: - val: object = settings.value(key) - if not val: - return default - return [s.strip().lower() for s in str(val).split(',')] - - pyzx.settings.tikz_classes = tikz_classes - pyzx.tikz.synonyms_boundary = _get_synonyms('tikz/boundary-import', pyzx.tikz.synonyms_boundary) - pyzx.tikz.synonyms_z = _get_synonyms('tikz/Z-spider-import', pyzx.tikz.synonyms_z) - pyzx.tikz.synonyms_x = _get_synonyms('tikz/X-spider-import', pyzx.tikz.synonyms_x) - pyzx.tikz.synonyms_hadamard = _get_synonyms('tikz/Hadamard-import', pyzx.tikz.synonyms_hadamard) - pyzx.tikz.synonyms_w_input = _get_synonyms('tikz/W-input-import', pyzx.tikz.synonyms_w_input) - pyzx.tikz.synonyms_w_output = _get_synonyms('tikz/W-output-import', pyzx.tikz.synonyms_w_output) - pyzx.tikz.synonyms_z_box = _get_synonyms('tikz/Z-box-import', pyzx.tikz.synonyms_z_box) - pyzx.tikz.synonyms_edge = _get_synonyms('tikz/edge-import', pyzx.tikz.synonyms_edge) - pyzx.tikz.synonyms_hedge = _get_synonyms('tikz/edge-H-import', pyzx.tikz.synonyms_hedge) - pyzx.tikz.synonyms_wedge = _get_synonyms('tikz/edge-W-import', pyzx.tikz.synonyms_wedge) - - -set_pyzx_tikz_settings() # Call it once on startup - - def to_tikz(g: GraphT) -> str: return pyzx.tikz.to_tikz(g) # type: ignore diff --git a/zxlive/edit_panel.py b/zxlive/edit_panel.py index d0e24807..9f281fd2 100644 --- a/zxlive/edit_panel.py +++ b/zxlive/edit_panel.py @@ -12,11 +12,12 @@ from .base_panel import ToolbarSection from .commands import UpdateGraph -from .common import GraphT, input_circuit_formats +from .common import GraphT from .dialogs import show_error_msg, create_circuit_dialog from .editor_base_panel import EditorBasePanel from .graphscene import EditGraphScene from .graphview import GraphView +from .settings_dialog import input_circuit_formats class GraphEditPanel(EditorBasePanel): diff --git a/zxlive/editor_base_panel.py b/zxlive/editor_base_panel.py index ad06122f..ff7ffe6f 100644 --- a/zxlive/editor_base_panel.py +++ b/zxlive/editor_base_panel.py @@ -19,10 +19,11 @@ from .commands import (AddEdge, AddNode, AddWNode, ChangeEdgeColor, ChangeNodeType, ChangePhase, MoveNode, SetGraph, UpdateGraph) -from .common import VT, GraphT, ToolType, get_data, colors +from .common import VT, GraphT, ToolType, get_data from .dialogs import show_error_msg from .eitem import HAD_EDGE_BLUE from .graphscene import EditGraphScene +from .settings import display_setting from .vitem import BLACK @@ -40,12 +41,12 @@ class DrawPanelNodeType(TypedDict): def vertices_data() -> dict[VertexType, DrawPanelNodeType]: return { - VertexType.Z: {"text": "Z spider", "icon": (ShapeType.CIRCLE, colors.z_spider)}, - VertexType.X: {"text": "X spider", "icon": (ShapeType.CIRCLE, colors.x_spider)}, - VertexType.H_BOX: {"text": "H box", "icon": (ShapeType.SQUARE, colors.hadamard)}, - VertexType.Z_BOX: {"text": "Z box", "icon": (ShapeType.SQUARE, colors.z_spider)}, - VertexType.W_OUTPUT: {"text": "W node", "icon": (ShapeType.TRIANGLE, colors.w_output)}, - VertexType.BOUNDARY: {"text": "boundary", "icon": (ShapeType.CIRCLE, colors.w_input)}, + VertexType.Z: {"text": "Z spider", "icon": (ShapeType.CIRCLE, display_setting.colors["z_spider"])}, + VertexType.X: {"text": "X spider", "icon": (ShapeType.CIRCLE, display_setting.colors["x_spider"])}, + VertexType.H_BOX: {"text": "H box", "icon": (ShapeType.SQUARE, display_setting.colors["hadamard"])}, + VertexType.Z_BOX: {"text": "Z box", "icon": (ShapeType.SQUARE, display_setting.colors["z_spider"])}, + VertexType.W_OUTPUT: {"text": "W node", "icon": (ShapeType.TRIANGLE, display_setting.colors["w_output"])}, + VertexType.BOUNDARY: {"text": "boundary", "icon": (ShapeType.CIRCLE, display_setting.colors["w_input"])}, } def edges_data() -> dict[EdgeType, DrawPanelNodeType]: diff --git a/zxlive/icons/folder.svg b/zxlive/icons/folder.svg new file mode 100644 index 00000000..758ad189 --- /dev/null +++ b/zxlive/icons/folder.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/zxlive/proof.py b/zxlive/proof.py index fc57cb9f..64db6caf 100644 --- a/zxlive/proof.py +++ b/zxlive/proof.py @@ -12,7 +12,8 @@ QStyle, QStyledItemDelegate, QStyleOptionViewItem, QWidget) -from .common import GraphT, colors +from .common import GraphT +from .settings import display_setting class Rewrite(NamedTuple): @@ -354,7 +355,7 @@ def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: Union[QM # Draw circle painter.setPen(QPen(Qt.GlobalColor.black, self.circle_outline_width)) - painter.setBrush(colors.z_spider) + painter.setBrush(display_setting.colors["z_spider"]) circle_radius = self.circle_radius_selected if option.state & QStyle.StateFlag.State_Selected else self.circle_radius painter.drawEllipse( QPointF(self.line_padding + self.line_width / 2, option.rect.y() + option.rect.height() / 2), diff --git a/zxlive/settings.py b/zxlive/settings.py new file mode 100644 index 00000000..003d4504 --- /dev/null +++ b/zxlive/settings.py @@ -0,0 +1,204 @@ +from __future__ import annotations + +from typing import Dict, Any, TypedDict + +import pyzx +from PySide6.QtCore import QSettings +from PySide6.QtGui import QColor +from PySide6.QtWidgets import QTabWidget + +from .common import get_settings_value, SCALE + + +class ColorScheme(TypedDict): + id: str + label: str + z_spider: QColor + z_spider_pressed: QColor + x_spider: QColor + x_spider_pressed: QColor + hadamard: QColor + hadamard_pressed: QColor + boundary: QColor + boundary_pressed: QColor + w_input: QColor + w_input_pressed: QColor + w_output: QColor + w_output_pressed: QColor + outline: QColor + + +general_defaults: Dict[str, str | QTabWidget.TabPosition | int] = { + "path/custom-rules": "lemmas/", + "color-scheme": "modern-red-green", + "tab-bar-location": QTabWidget.TabPosition.North, + "snap-granularity": '4', + "input-circuit-format": 'openqasm', +} + +tikz_export_defaults: dict[str, str] = { + "tikz/boundary-export": pyzx.settings.tikz_classes['boundary'], + "tikz/Z-spider-export": pyzx.settings.tikz_classes['Z'], + "tikz/X-spider-export": pyzx.settings.tikz_classes['X'], + "tikz/Z-phase-export": pyzx.settings.tikz_classes['Z phase'], + "tikz/X-phase-export": pyzx.settings.tikz_classes['X phase'], + "tikz/z-box-export": pyzx.settings.tikz_classes['Z box'], + "tikz/Hadamard-export": pyzx.settings.tikz_classes['H'], + "tikz/w-output-export": pyzx.settings.tikz_classes['W'], + "tikz/w-input-export": pyzx.settings.tikz_classes['W input'], + "tikz/edge-export": pyzx.settings.tikz_classes['edge'], + "tikz/edge-H-export": pyzx.settings.tikz_classes['H-edge'], + "tikz/edge-W-export": pyzx.settings.tikz_classes['W-io-edge'], +} + +tikz_import_defaults: dict[str, str] = { + "tikz/boundary-import": ", ".join(pyzx.tikz.synonyms_boundary), + "tikz/Z-spider-import": ", ".join(pyzx.tikz.synonyms_z), + "tikz/X-spider-import": ", ".join(pyzx.tikz.synonyms_x), + "tikz/Hadamard-import": ", ".join(pyzx.tikz.synonyms_hadamard), + "tikz/w-input-import": ", ".join(pyzx.tikz.synonyms_w_input), + "tikz/w-output-import": ", ".join(pyzx.tikz.synonyms_w_output), + "tikz/z-box-import": ", ".join(pyzx.tikz.synonyms_z_box), + "tikz/edge-import": ", ".join(pyzx.tikz.synonyms_edge), + "tikz/edge-H-import": ", ".join(pyzx.tikz.synonyms_hedge), + "tikz/edge-W-import": ", ".join(pyzx.tikz.synonyms_wedge), +} + +tikz_layout_defaults: dict[str, float] = { + "tikz/layout/hspace": 2.0, + "tikz/layout/vspace": 2.0, + "tikz/layout/max-width": 10.0, +} + +tikz_names_defaults: dict[str, str] = { + "tikz/names/fuse spiders": "f", + "tikz/names/bialgebra": "b", + "tikz/names/change color to Z": "cc", + "tikz/names/change color to X": "cc", + "tikz/names/remove identity": "id", + "tikz/names/Add Z identity": "id", + "tikz/names/copy 0/pi spider": "cp", + "tikz/names/push Pauli": "pi", + "tikz/names/decompose hadamard": "eu", +} + +defaults = general_defaults | tikz_export_defaults | tikz_import_defaults \ + | tikz_layout_defaults | tikz_names_defaults + + +modern_red_green: ColorScheme = { + "id": 'modern-red-green', + "label": "Modern Red & Green", + "z_spider": QColor("#ccffcc"), + "z_spider_pressed": QColor("#64BC90"), + "x_spider": QColor("#ff8888"), + "x_spider_pressed": QColor("#bb0f0f"), + "hadamard": QColor("#ffff00"), + "hadamard_pressed": QColor("#f1c232"), + "boundary": QColor("#000000"), + "boundary_pressed": QColor("#444444"), + "w_input": QColor("#000000"), + "w_input_pressed": QColor("#444444"), + "w_output": QColor("#000000"), + "w_output_pressed": QColor("#444444"), + "outline": QColor("#000000"), +} + +classic_red_green: ColorScheme = modern_red_green | { + "id": "classic-red-green", + "label": "Classic Red & Green", + "z_spider": QColor("#00ff00"), + "z_spider_pressed": QColor("#00dd00"), + "x_spider": QColor("#ff0d00"), + "x_spider_pressed": QColor("#dd0b00"), +} + +white_gray: ColorScheme = modern_red_green | { + "id": 'white-grey', + "label": "Dodo book White & Grey", + "z_spider": QColor("#ffffff"), + "z_spider_pressed": QColor("#eeeeee"), + "x_spider": QColor("#b4b4b4"), + "x_spider_pressed": QColor("#a0a0a0"), + "hadamard": QColor("#ffffff"), + "hadamard_pressed": QColor("#dddddd"), +} + +gidney: ColorScheme = white_gray | { + "id": 'gidney', + "label": "Gidney's Black & White", + "z_spider": QColor("#000000"), + "z_spider_pressed": QColor("#222222"), + "x_spider": QColor("#ffffff"), + "x_spider_pressed": QColor("#dddddd"), +} + +color_schemes = { + scheme["id"]: scheme for scheme in [modern_red_green, classic_red_green, white_gray, gidney] +} + +color_scheme_ids = list(color_schemes.keys()) + + +def load_tikz_classes() -> dict[str, str]: + return { + 'boundary': str(settings.value('tikz/boundary-export', pyzx.settings.tikz_classes['boundary'])), + 'Z': str(settings.value('tikz/Z-spider-export', pyzx.settings.tikz_classes['Z'])), + 'X': str(settings.value('tikz/X-spider-export', pyzx.settings.tikz_classes['X'])), + 'Z phase': str(settings.value('tikz/Z-phase-export', pyzx.settings.tikz_classes['Z phase'])), + 'X phase': str(settings.value('tikz/X-phase-export', pyzx.settings.tikz_classes['X phase'])), + 'Z box': str(settings.value('tikz/Z-box-export', pyzx.settings.tikz_classes['Z box'])), + 'H': str(settings.value('tikz/Hadamard-export', pyzx.settings.tikz_classes['H'])), + 'W': str(settings.value('tikz/W-output-export', pyzx.settings.tikz_classes['W'])), + 'W input': str(settings.value('tikz/W-input-export', pyzx.settings.tikz_classes['W input'])), + 'edge': str(settings.value('tikz/edge-export', pyzx.settings.tikz_classes['edge'])), + 'H-edge': str(settings.value('tikz/edge-H-export', pyzx.settings.tikz_classes['H-edge'])), + 'W-io-edge': str(settings.value('tikz/edge-W-export', pyzx.settings.tikz_classes['W-io-edge'])), + } + + +def refresh_pyzx_tikz_settings() -> None: + def _get_synonyms(key: str, default: list[str]) -> list[str]: + val: object = settings.value(key) + if not val: + return default + return [s.strip().lower() for s in str(val).split(',')] + + pyzx.settings.tikz_classes = load_tikz_classes() + pyzx.tikz.synonyms_boundary = _get_synonyms('tikz/boundary-import', pyzx.tikz.synonyms_boundary) + pyzx.tikz.synonyms_z = _get_synonyms('tikz/Z-spider-import', pyzx.tikz.synonyms_z) + pyzx.tikz.synonyms_x = _get_synonyms('tikz/X-spider-import', pyzx.tikz.synonyms_x) + pyzx.tikz.synonyms_hadamard = _get_synonyms('tikz/Hadamard-import', pyzx.tikz.synonyms_hadamard) + pyzx.tikz.synonyms_w_input = _get_synonyms('tikz/W-input-import', pyzx.tikz.synonyms_w_input) + pyzx.tikz.synonyms_w_output = _get_synonyms('tikz/W-output-import', pyzx.tikz.synonyms_w_output) + pyzx.tikz.synonyms_z_box = _get_synonyms('tikz/Z-box-import', pyzx.tikz.synonyms_z_box) + pyzx.tikz.synonyms_edge = _get_synonyms('tikz/edge-import', pyzx.tikz.synonyms_edge) + pyzx.tikz.synonyms_hedge = _get_synonyms('tikz/edge-H-import', pyzx.tikz.synonyms_hedge) + pyzx.tikz.synonyms_wedge = _get_synonyms('tikz/edge-W-import', pyzx.tikz.synonyms_wedge) + + +class DisplaySettings: + SNAP_DIVISION = 4 # Should be an integer dividing SCALE + + def __init__(self, scheme_id: str) -> None: + self.colors = color_schemes[scheme_id] + self.update() + + def set_color_scheme(self, scheme_id: str) -> None: + self.colors = color_schemes[scheme_id] + + def update(self) -> None: + self.SNAP_DIVISION = int(get_settings_value("snap-granularity", str)) + self.SNAP = SCALE / self.SNAP_DIVISION + + +# Initialise settings +settings = QSettings("zxlive", "zxlive") +for key, value in defaults.items(): + if not settings.contains(key): + settings.setValue(key, value) + +refresh_pyzx_tikz_settings() # Call it once on startup + + +display_setting = DisplaySettings(str(settings.value("color-scheme"))) diff --git a/zxlive/settings_dialog.py b/zxlive/settings_dialog.py index 76d62357..63064df9 100644 --- a/zxlive/settings_dialog.py +++ b/zxlive/settings_dialog.py @@ -15,168 +15,160 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Dict, Any, Optional, Union +from enum import IntEnum +from typing import TYPE_CHECKING, Dict, Any -from PySide6.QtCore import QSettings -from PySide6.QtWidgets import (QDialog, QFileDialog, - QFormLayout, QLineEdit, - QPushButton, QWidget, - QVBoxLayout, QSpinBox, QDoubleSpinBox, - QLabel, QHBoxLayout, QTabWidget, - QComboBox) +from PySide6.QtGui import QIcon +from typing_extensions import TypedDict, NotRequired -import pyzx +from PySide6.QtCore import QSettings +from PySide6.QtWidgets import ( + QDialog, QFileDialog, QFormLayout, QLineEdit, QPushButton, QWidget, + QVBoxLayout, QSpinBox, QDoubleSpinBox, QLabel, QHBoxLayout, QTabWidget, + QComboBox +) -from .common import set_pyzx_tikz_settings, colors, setting, color_schemes, input_circuit_formats, defaults +from .common import get_settings_value, T, get_data +from .settings import ( + refresh_pyzx_tikz_settings, defaults, display_setting, color_schemes +) if TYPE_CHECKING: from .mainwindow import MainWindow +class FormInputType(IntEnum): + Str = 0 + Int = 1 + Float = 2 + Folder = 3 + Combo = 4 + + +class SettingsData(TypedDict): + id: str + label: str + type: FormInputType + data: NotRequired[dict[Any, str]] + + +color_scheme_data = { + id: scheme["label"] for id, scheme in color_schemes.items() +} + +tab_positioning_data = { + QTabWidget.TabPosition.North: "Top", + QTabWidget.TabPosition.South: "Bottom", + QTabWidget.TabPosition.West: "Left", + QTabWidget.TabPosition.East: "Right" +} + +snap_to_grid_data = {'2': "2", '4': "4", '8': "8", '16': "16"} + +input_circuit_formats = { + 'openqasm': "standard OpenQASM", + 'sqasm': "Spider QASM", + 'sqasm-no-simplification': "Spider QASM (no simplification)", +} + + +general_settings: list[SettingsData] = [ + {"id": "path/custom-rules", "label": "Custom rules path", "type": FormInputType.Folder}, + {"id": "color-scheme", "label": "Color scheme", "type": FormInputType.Combo, "data": color_scheme_data}, + {"id": "tab-bar-location", "label": "Tab bar location", "type": FormInputType.Combo, "data": tab_positioning_data}, + {"id": "snap-granularity", "label": "Snap-to-grid granularity", "type": FormInputType.Combo, "data": snap_to_grid_data}, + {"id": "input-circuit-format", "label": "Input Circuit as", "type": FormInputType.Combo, "data": input_circuit_formats}, +] + +tikz_export_settings: list[SettingsData] = [ + {"id": "tikz/Z-spider-export", "label": "Z-spider", "type": FormInputType.Str}, + {"id": "tikz/Z-phase-export", "label": "Z-spider with phase", "type": FormInputType.Str}, + {"id": "tikz/X-spider-export", "label": "X-spider", "type": FormInputType.Str}, + {"id": "tikz/X-phase-export", "label": "X-spider with phase", "type": FormInputType.Str}, + {"id": "tikz/Hadamard-export", "label": "Hadamard", "type": FormInputType.Str}, + {"id": "tikz/w-input-export", "label": "W input", "type": FormInputType.Str}, + {"id": "tikz/w-output-export", "label": "W output", "type": FormInputType.Str}, + {"id": "tikz/z-box-export", "label": "Z box", "type": FormInputType.Str}, + {"id": "tikz/edge-W-export", "label": "W io edge", "type": FormInputType.Str}, +] + +tikz_import_settings: list[SettingsData] = [ + {"id": "tikz/Z-spider-import", "label": "Z-spider", "type": FormInputType.Str}, + {"id": "tikz/w-input-import", "label": "W input", "type": FormInputType.Str}, + {"id": "tikz/w-output-import", "label": "W output", "type": FormInputType.Str}, + {"id": "tikz/z-box-import", "label": "Z box", "type": FormInputType.Str}, + {"id": "tikz/edge-W-import", "label": "W io edge", "type": FormInputType.Str}, +] + +tikz_layout_settings: list[SettingsData] = [ + {"id": "tikz/layout/hspace", "label": "Horizontal spacing", "type": FormInputType.Float}, + {"id": "tikz/layout/vspace", "label": "Vertical spacing", "type": FormInputType.Float}, + {"id": "tikz/layout/max-width", "label": "Maximum width", "type": FormInputType.Float}, +] + +tikz_rule_name_settings: list[SettingsData] = [ + {"id": "tikz/names/fuse spiders", "label": "fuse spiders", "type": FormInputType.Str}, + {"id": "tikz/names/bialgebra", "label": "bialgebra", "type": FormInputType.Str}, + {"id": "tikz/names/change color to Z", "label": "change color to Z", "type": FormInputType.Str}, + {"id": "tikz/names/change color to X", "label": "change color to X", "type": FormInputType.Str}, + {"id": "tikz/names/remove identity", "label": "remove identity", "type": FormInputType.Str}, + {"id": "tikz/names/Add Z identity", "label": "add Z identity", "type": FormInputType.Str}, + {"id": "tikz/names/copy 0/pi spider", "label": "copy 0/pi spider", "type": FormInputType.Str}, + {"id": "tikz/names/push Pauli", "label": "push Pauli", "type": FormInputType.Str}, + {"id": "tikz/names/decompose hadamard", "label": "decompose hadamard", "type": FormInputType.Str}, +] + + class SettingsDialog(QDialog): def __init__(self, main_window: MainWindow) -> None: super().__init__(main_window) self.main_window = main_window self.setWindowTitle("Settings") + self.settings = QSettings("zxlive", "zxlive") - self.value_dict: Dict[str,QWidget] = {} + self.value_dict: Dict[str, QWidget] = {} + self.prev_color_scheme = self.get_settings_value("color-scheme", str) + self.prev_tab_bar_location = self.get_settings_value("tab-bar-location", QTabWidget.TabPosition) layout = QVBoxLayout() - self.setLayout(layout) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) + self.setLayout(layout) tab_widget = QTabWidget() layout.addWidget(tab_widget) - ##### General settings ##### - panel_base_settings = QWidget() - vlayout = QVBoxLayout() - panel_base_settings.setLayout(vlayout) - tab_widget.addTab(panel_base_settings, "General") - vlayout.addWidget(QLabel("General ZXLive settings")) - form_general = QFormLayout() - w = QWidget() - w.setLayout(form_general) - vlayout.addWidget(w) - self.add_setting(form_general, "path/custom-rules", "Custom rules path", 'folder') - self.add_setting(form_general, "color-scheme", "Color scheme", 'combo',data=color_schemes) - self.add_setting(form_general, "tab-bar-location", "Tab bar location", 'combo', data={ - QTabWidget.TabPosition.North: "Top", QTabWidget.TabPosition.South: "Bottom", - QTabWidget.TabPosition.West: "Left", QTabWidget.TabPosition.East: "Right"}) - self.add_setting(form_general, "snap-granularity", "Snap-to-grid granularity", 'combo', - data = {'2': "2", '4': "4", '8': "8", '16': "16"}) - self.add_setting(form_general, "input-circuit-format", "Input Circuit as", 'combo', data=input_circuit_formats) - self.prev_color_scheme = self.settings.value("color-scheme") - self.prev_tab_bar_location = self.settings.value("tab-bar-location") - vlayout.addStretch() + self.add_settings_tab(tab_widget, "General", "General ZXLive settings", general_settings) + self.add_settings_tab(tab_widget, "Tikz rule names", "Tikz rule name settings", tikz_rule_name_settings) + self.add_settings_tab(tab_widget, "Tikz export", "These are the class names that will be used when exporting to tikz.", tikz_export_settings) + self.add_settings_tab(tab_widget, "Tikz import", "These are the class names that are understood when importing from tikz.", tikz_import_settings) + self.add_settings_tab(tab_widget, "Tikz layout", "Tikz layout settings", tikz_layout_settings) - ##### Tikz Export settings ##### - panel_tikz_export = QWidget() - vlayout = QVBoxLayout() - panel_tikz_export.setLayout(vlayout) - tab_widget.addTab(panel_tikz_export, "Tikz export") + self.init_okay_cancel_buttons(layout) - vlayout.addWidget(QLabel("Tikz export settings")) - vlayout.addWidget(QLabel("These are the class names that will be used when exporting to tikz.")) + def get_settings_value(self, arg: str, _type: type[T], default: T | None = None) -> T: + return get_settings_value(arg, _type, default, self.settings) - form_export = QFormLayout() - w = QWidget() - w.setLayout(form_export) - vlayout.addWidget(w) - vlayout.addStretch() + def get_settings_from_data(self, data: SettingsData, _type: type[T]) -> T: + name = data["id"] + assert isinstance(default := defaults[name], _type) + return self.get_settings_value(name, _type, default) - self.add_setting(form_export, "tikz/Z-spider-export", "Z-spider", 'str') - self.add_setting(form_export, "tikz/Z-phase-export", "Z-spider with phase", 'str') - self.add_setting(form_export, "tikz/X-spider-export", "X-spider", 'str') - self.add_setting(form_export, "tikz/X-phase-export", "X-spider with phase", 'str') - self.add_setting(form_export, "tikz/Hadamard-export", "Hadamard", 'str') - self.add_setting(form_export, "tikz/boundary-export", "Boundary", 'str') - self.add_setting(form_export, "tikz/edge-export", "Regular Edge", 'str') - self.add_setting(form_export, "tikz/edge-H-export", "Hadamard edge", 'str') - - self.add_setting(form_export, "tikz/w-input-export", "W input", 'str') - self.add_setting(form_export, "tikz/w-output-export", "W output", 'str') - self.add_setting(form_export, "tikz/z-box-export", "Z box", 'str') - self.add_setting(form_export, "tikz/edge-W-export", "W io edge", 'str') - - - ##### Tikz Import settings ##### - panel_tikz_import = QWidget() - vlayout = QVBoxLayout() - panel_tikz_import.setLayout(vlayout) - tab_widget.addTab(panel_tikz_import, "Tikz import") - - vlayout.addWidget(QLabel("Tikz import settings")) - vlayout.addWidget(QLabel("These are the class names that are understood when importing from tikz.")) - - form_import = QFormLayout() - w = QWidget() - w.setLayout(form_import) - vlayout.addWidget(w) - vlayout.addStretch() - self.add_setting(form_import, "tikz/Z-spider-import", "Z-spider", 'str') - self.add_setting(form_import, "tikz/X-spider-import", "X-spider", 'str') - self.add_setting(form_import, "tikz/Hadamard-import", "Hadamard", 'str') - self.add_setting(form_import, "tikz/boundary-import", "Boundary", 'str') - self.add_setting(form_import, "tikz/edge-import", "Regular Edge", 'str') - self.add_setting(form_import, "tikz/edge-H-import", "Hadamard edge", 'str') - - self.add_setting(form_import, "tikz/w-input-import", "W input", 'str') - self.add_setting(form_import, "tikz/w-output-import", "W output", 'str') - self.add_setting(form_import, "tikz/z-box-import", "Z box", 'str') - self.add_setting(form_import, "tikz/edge-W-import", "W io edge", 'str') - - ##### Tikz Layout settings ##### - panel_tikz_layout = QWidget() - vlayout = QVBoxLayout() - panel_tikz_layout.setLayout(vlayout) - tab_widget.addTab(panel_tikz_layout, "Tikz layout") - - vlayout.addWidget(QLabel("Tikz layout settings")) - - form_layout = QFormLayout() - w = QWidget() - w.setLayout(form_layout) - vlayout.addWidget(w) - vlayout.addStretch() - - self.add_setting(form_layout, "tikz/layout/hspace", "Horizontal spacing", "float") - self.add_setting(form_layout, "tikz/layout/vspace", "Vertical spacing", "float") - self.add_setting(form_layout, "tikz/layout/max-width", "Maximum width", 'float') - - - ##### Tikz rule name settings ##### - panel_tikz_names = QWidget() - vlayout = QVBoxLayout() + def add_settings_tab(self, tab_widget: QTabWidget, tab_name: str, label: str, data: list[SettingsData]) -> None: + panel_tikz_names, vlayout = QWidget(), QVBoxLayout() panel_tikz_names.setLayout(vlayout) - tab_widget.addTab(panel_tikz_names, "Tikz rule names") - - vlayout.addWidget(QLabel("Tikz rule name settings")) - vlayout.addWidget(QLabel("Mapping of pyzx rule names to tikz display strings")) - - form_names = QFormLayout() - w = QWidget() + tab_widget.addTab(panel_tikz_names, tab_name) + vlayout.addWidget(QLabel(label)) + form_names, w = QFormLayout(), QWidget() w.setLayout(form_names) vlayout.addWidget(w) vlayout.addStretch() + for d in data: + self.add_setting_to_form(form_names, d) - self.add_setting(form_names, "tikz/names/fuse spiders", "fuse spiders", "str") - self.add_setting(form_names, "tikz/names/bialgebra", "bialgebra", "str") - self.add_setting(form_names, "tikz/names/change color to Z", "change color to Z", "str") - self.add_setting(form_names, "tikz/names/change color to X", "change color to X", "str") - self.add_setting(form_names, "tikz/names/remove identity", "remove identity", "str") - self.add_setting(form_names, "tikz/names/Add Z identity", "add Z identity", "str") - self.add_setting(form_names, "tikz/names/copy 0/pi spider", "copy 0/pi spider", "str") - self.add_setting(form_names, "tikz/names/push Pauli", "push Pauli", "str") - self.add_setting(form_names, "tikz/names/decompose hadamard", "decompose hadamard", "str") - - - - ##### Okay/Cancel Buttons ##### - w= QWidget() - hlayout = QHBoxLayout() + def init_okay_cancel_buttons(self, layout: QVBoxLayout) -> None: + w, hlayout = QWidget(), QHBoxLayout() hlayout.addStretch() w.setLayout(hlayout) layout.addWidget(w) @@ -187,49 +179,72 @@ def __init__(self, main_window: MainWindow) -> None: cancel_button.clicked.connect(self.cancel) hlayout.addWidget(cancel_button) - - def add_setting(self,form:QFormLayout, name:str, label:str, ty:str, data: Optional[dict[Any, str]] = None) -> None: - val = self.settings.value(name) - widget: Union[QWidget, QLineEdit, QSpinBox, QDoubleSpinBox, QComboBox] - if val is None: val = defaults[name] - if ty == 'str': - widget = QLineEdit() - val = str(val) - widget.setText(val) - elif ty == 'int': - widget = QSpinBox() - widget.setValue(int(val)) # type: ignore - elif ty == 'float': - widget = QDoubleSpinBox() - widget.setValue(float(val)) # type: ignore - elif ty == 'folder': - widget = QWidget() - hlayout = QHBoxLayout() - widget.setLayout(hlayout) - widget_line = QLineEdit() - widget_line.setText(str(val)) - def browse() -> None: - directory = QFileDialog.getExistingDirectory(self,"Pick folder",options=QFileDialog.Option.ShowDirsOnly) - if directory: - widget_line.setText(directory) - setattr(widget, "text_value", directory) - hlayout.addWidget(widget_line) - button = QPushButton("Browse") - button.clicked.connect(browse) - hlayout.addWidget(button) - elif ty == 'combo': - widget = QComboBox() - assert data is not None - widget.addItems(list(data.values())) - widget.setCurrentText(data[val]) - setattr(widget, "data", data) - - - form.addRow(label, widget) - self.value_dict[name] = widget + def make_str_form_input(self, data: SettingsData) -> QLineEdit: + widget = QLineEdit() + widget.setText(self.get_settings_from_data(data, str)) + return widget + + def make_int_form_input(self, data: SettingsData) -> QSpinBox: + widget = QSpinBox() + widget.setValue(self.get_settings_from_data(data, int)) + return widget + + def make_float_form_input(self, data: SettingsData) -> QDoubleSpinBox: + widget = QDoubleSpinBox() + widget.setValue(self.get_settings_from_data(data, float)) + return widget + + def make_folder_form_input(self, data: SettingsData) -> QLineEdit: + widget_line = QLineEdit() + widget_line.setText(self.get_settings_from_data(data, str)) + + def browse() -> None: + directory = QFileDialog.getExistingDirectory( + self,"Pick folder", options=QFileDialog.Option.ShowDirsOnly + ) + if directory: + widget_line.setText(directory) + + action = widget_line.addAction( + QIcon(get_data("icons/folder.svg")), QLineEdit.ActionPosition.TrailingPosition + ) + action.setToolTip("Browse...") + action.triggered.connect(browse) + # It would be nice to highlight the icon on hover + + return widget_line + + def make_combo_form_input(self, data: SettingsData) -> QComboBox: + assert "data" in data + name, _data = data["id"], data["data"] + value = self.settings.value(name, defaults[name]) + widget = QComboBox() + for k, v in _data.items(): + widget.addItem(v, userData=k) + widget.setCurrentText(_data[value]) + return widget + + def add_setting_to_form(self, form: QFormLayout, settings_data: SettingsData) -> None: + setting_maker = { + FormInputType.Str: self.make_str_form_input, + FormInputType.Int: self.make_int_form_input, + FormInputType.Float: self.make_float_form_input, + FormInputType.Folder: self.make_folder_form_input, + FormInputType.Combo: self.make_combo_form_input, + } + setting_widget_maker = setting_maker[settings_data["type"]] + widget: QWidget = setting_widget_maker(settings_data) + + form.addRow(settings_data["label"], widget) + self.value_dict[settings_data["id"]] = widget def okay(self) -> None: - for name,widget in self.value_dict.items(): + self.update_global_settings() + self.apply_global_settings() + self.accept() + + def update_global_settings(self) -> None: + for name, widget in self.value_dict.items(): if isinstance(widget, QLineEdit): self.settings.setValue(name, widget.text()) elif isinstance(widget, QSpinBox): @@ -237,31 +252,23 @@ def okay(self) -> None: elif isinstance(widget, QDoubleSpinBox): self.settings.setValue(name, widget.value()) elif isinstance(widget, QComboBox): - s = widget.currentText() - assert hasattr(widget, "data") - val = next(k for k in widget.data if widget.data[k] == s) - self.settings.setValue(name, val) - elif isinstance(widget, QWidget) and hasattr(widget, "text_value"): - self.settings.setValue(name, widget.text_value) - set_pyzx_tikz_settings() - setting.update() - if self.settings.value("color-scheme") != self.prev_color_scheme: - theme = self.settings.value("color-scheme") - assert isinstance(theme, str) - colors.set_color_scheme(theme) + self.settings.setValue(name, widget.currentData()) + display_setting.update() + + def apply_global_settings(self) -> None: + refresh_pyzx_tikz_settings() + theme = self.get_settings_value("color-scheme", str) + if theme != self.prev_color_scheme: + display_setting.set_color_scheme(theme) self.main_window.update_colors() - if self.settings.value("tab-bar-location") != self.prev_tab_bar_location: - pos = self.settings.value("tab-bar-location") - assert isinstance(pos, QTabWidget.TabPosition) + pos = self.get_settings_value("tab-bar-location", QTabWidget.TabPosition) + if pos != self.prev_tab_bar_location: self.main_window.tab_widget.setTabPosition(pos) - self.accept() def cancel(self) -> None: self.reject() - - def open_settings_dialog(parent: MainWindow) -> None: dialog = SettingsDialog(parent) dialog.exec() diff --git a/zxlive/tikz.py b/zxlive/tikz.py index c9b3e40e..538d65da 100644 --- a/zxlive/tikz.py +++ b/zxlive/tikz.py @@ -1,14 +1,15 @@ from PySide6.QtCore import QSettings from pyzx.tikz import TIKZ_BASE, _to_tikz +from .common import get_settings_value from zxlive.proof import ProofModel def proof_to_tikz(proof: ProofModel) -> str: settings = QSettings("zxlive", "zxlive") - vspace = float(settings.value("tikz/layout/vspace")) - hspace = float(settings.value("tikz/layout/hspace")) - max_width = float(settings.value("tikz/layout/max-width")) + vspace = get_settings_value("tikz/layout/vspace", float, settings=settings) + hspace = get_settings_value("tikz/layout/hspace", float, settings=settings) + max_width = get_settings_value("tikz/layout/max-width", float, settings=settings) draw_scalar = False xoffset = -max_width diff --git a/zxlive/vitem.py b/zxlive/vitem.py index 593de311..5e6391ee 100644 --- a/zxlive/vitem.py +++ b/zxlive/vitem.py @@ -28,7 +28,8 @@ from pyzx.utils import VertexType, phase_to_s, get_w_partner, vertex_is_w, get_z_box_label -from .common import VT, W_INPUT_OFFSET, GraphT, SCALE, setting, pos_to_view, pos_from_view, colors +from .common import VT, W_INPUT_OFFSET, GraphT, SCALE, pos_to_view, pos_from_view +from .settings import display_setting if TYPE_CHECKING: from .eitem import EItem @@ -123,20 +124,20 @@ def refresh(self) -> None: if not self.isSelected(): t = self.ty if t == VertexType.Z or t == VertexType.Z_BOX: - self.setBrush(QBrush(colors.z_spider)) + self.setBrush(QBrush(display_setting.colors["z_spider"])) elif t == VertexType.X: - self.setBrush(QBrush(colors.x_spider)) + self.setBrush(QBrush(display_setting.colors["x_spider"])) elif t == VertexType.H_BOX: - self.setBrush(QBrush(colors.hadamard)) + self.setBrush(QBrush(display_setting.colors["hadamard"])) elif t == VertexType.W_INPUT: - self.setBrush(QBrush(colors.w_input)) + self.setBrush(QBrush(display_setting.colors["w_input"])) elif t == VertexType.W_OUTPUT: - self.setBrush(QBrush(colors.w_output)) + self.setBrush(QBrush(display_setting.colors["w_output"])) else: - self.setBrush(QBrush(colors.boundary)) + self.setBrush(QBrush(display_setting.colors["boundary"])) pen = QPen() pen.setWidthF(3) - pen.setColor(colors.outline) + pen.setColor(display_setting.colors["outline"]) self.setPen(pen) if self.isSelected(): @@ -144,30 +145,30 @@ def refresh(self) -> None: pen.setWidthF(5) t = self.ty if t == VertexType.Z or t == VertexType.Z_BOX: - brush = QBrush(colors.z_spider_pressed) + brush = QBrush(display_setting.colors["z_spider_pressed"]) brush.setStyle(Qt.BrushStyle.Dense1Pattern) self.setBrush(brush) elif t == VertexType.X: - brush = QBrush(colors.x_spider_pressed) + brush = QBrush(display_setting.colors["x_spider_pressed"]) brush.setStyle(Qt.BrushStyle.Dense1Pattern) self.setBrush(brush) elif t == VertexType.H_BOX: - brush = QBrush(colors.hadamard_pressed) + brush = QBrush(display_setting.colors["hadamard_pressed"]) brush.setStyle(Qt.BrushStyle.Dense1Pattern) self.setBrush(brush) elif t == VertexType.W_INPUT: - brush = QBrush(colors.w_input_pressed) + brush = QBrush(display_setting.colors["w_input_pressed"]) brush.setStyle(Qt.BrushStyle.Dense1Pattern) self.setBrush(brush) elif t == VertexType.W_OUTPUT: - brush = QBrush(colors.w_output_pressed) + brush = QBrush(display_setting.colors["w_output_pressed"]) brush.setStyle(Qt.BrushStyle.Dense1Pattern) self.setBrush(brush) else: - brush = QBrush(colors.boundary_pressed) + brush = QBrush(display_setting.colors["boundary_pressed"]) brush.setStyle(Qt.BrushStyle.Dense1Pattern) self.setBrush(brush) - pen.setColor(colors.boundary_pressed) + pen.setColor(display_setting.colors["boundary_pressed"]) self.prepareGeometryChange() self.setPen(pen) @@ -184,7 +185,7 @@ def refresh(self) -> None: def update_shape(self) -> None: pen = QPen() pen.setWidthF(3) - pen.setColor(colors.outline) + pen.setColor(display_setting.colors["outline"]) self.setPen(pen) path = QPainterPath() @@ -236,8 +237,8 @@ def itemChange(self, change: QGraphicsItem.GraphicsItemChange, value: Any) -> An x = value.x() y = value.y() else: - x = round(value.x() / setting.SNAP) * setting.SNAP - y = round(value.y() / setting.SNAP) * setting.SNAP + x = round(value.x() / display_setting.SNAP) * display_setting.SNAP + y = round(value.y() / display_setting.SNAP) * display_setting.SNAP return QPointF(x, y) # When selecting/deselecting items, we move them to the front/back