class PlotControlWidget(QWidget): # noinspection PyTypeChecker def __init__(self, parent=None): super().__init__(parent) # setup settings for the class self.settings = QSettings() self.settings.beginGroup("plot_control") self.base_vector_data = vpype.VectorData() self.vector_data: vpype.VectorData = None # settings self.page_format: str = self.settings.value("page_format", "A4") self.landscape: bool = self.settings.value("landscape", False) self.rotated: bool = self.settings.value("rotate", False) self.rotated: bool = self.settings.value("rotated", False) self.center: bool = self.settings.value("center", True) self.fit_page: bool = self.settings.value("fit_page", False) self.margin_value: float = self.settings.value("margin_value", 2.0) self.margin_unit: str = self.settings.value("margin_unit", "cm") # setup plot area self.plot = VectorDataPlotWidget() self.plot.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) # page layout controls page_box = QGroupBox("Page layout") page_layout = QFormLayout() page_format_combo = QComboBox() for k in PAGE_FORMATS: page_format_combo.addItem(k) page_format_combo.setCurrentText(self.page_format) page_format_combo.currentTextChanged.connect( lambda text: self.set_page_format(text)) landscape_check = QCheckBox("Landscape") landscape_check.setChecked(self.landscape) landscape_check.stateChanged.connect( lambda: self.set_landscape(landscape_check.isChecked())) rotated_check = QCheckBox("Rotated") rotated_check.setChecked(self.landscape) rotated_check.stateChanged.connect( lambda: self.set_rotated(rotated_check.isChecked())) center_check = QCheckBox("Center on page") center_check.setChecked(self.center) center_check.stateChanged.connect( lambda: self.set_center(center_check.isChecked())) fit_page_check = QCheckBox("Fit to page") fit_page_check.setChecked(self.fit_page) fit_page_check.stateChanged.connect( lambda: self.set_fit_page(fit_page_check.isChecked())) margin_layout = QHBoxLayout() margin_spin = QDoubleSpinBox() margin_spin.setValue(self.margin_value) margin_spin.valueChanged.connect(lambda: self.set_margin( margin_spin.value(), margin_unit.currentText())) margin_unit = UnitComboBox() margin_unit.setCurrentText(self.margin_unit) margin_unit.currentTextChanged.connect(lambda: self.set_margin( margin_spin.value(), margin_unit.currentText())) margin_layout.addWidget(margin_spin) margin_layout.addWidget(margin_unit) page_layout.addRow("Page format:", page_format_combo) page_layout.addRow("", landscape_check) page_layout.addRow("", rotated_check) page_layout.addRow("", center_check) page_layout.addRow("", fit_page_check) page_layout.addRow("Margin:", margin_layout) page_box.setLayout(page_layout) # Action buttons pen_up_btn = QPushButton("UP") pen_down_btn = QPushButton("DOWN") pen_up_btn.clicked.connect(lambda: axy.pen_up()) pen_down_btn.clicked.connect(lambda: axy.pen_down()) pen_up_spin = AxySettingsSpinBox(self.settings, "pen_pos_up", 60.0) pen_down_spin = AxySettingsSpinBox(self.settings, "pen_pos_down", 40.0) pen_up_layout = QHBoxLayout() pen_up_layout.addWidget(pen_up_spin) pen_up_layout.addWidget(pen_up_btn) pen_down_layout = QHBoxLayout() pen_down_layout.addWidget(pen_down_spin) pen_down_layout.addWidget(pen_down_btn) shutdown_btn = QPushButton("OFF") shutdown_btn.clicked.connect(lambda: axy.shutdown()) plot_btn = QPushButton("PLOT") plot_btn.clicked.connect(lambda: self.plot_svg()) action_box = QGroupBox("Actions") action_layout = QFormLayout() action_layout.addRow("Pen up: ", pen_up_layout) action_layout.addRow("Pen down: ", pen_down_layout) action_layout.addRow("Motor off:", shutdown_btn) action_layout.addRow("Plot:", plot_btn) action_box.setLayout(action_layout) self.list = QListView() self.list.setFixedHeight(120) self.list.setSizePolicy( QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)) # controls layout controls_layout = QVBoxLayout() controls_layout.addWidget(self.list) controls_layout.addWidget(page_box) controls_layout.addWidget(action_box) controls_layout.addItem( QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)) # setup layout root_layout = QHBoxLayout() root_layout.addWidget(self.plot) root_layout.addLayout(controls_layout) self.setLayout(root_layout) self.update_view() # FIXME: stub vector data # vd = vpype.VectorData() # vd.add(vpype.LineCollection([(0, 100), (200, 1001 + 201j)]), 1) # vd.add(vpype.LineCollection([(0, 100 + 100j), (300j, 400j + 100)]), 2) self.load_svg( "/Users/hhip/Drive/axidraw/wheel_cards/wheel_card_triple_5_40.svg") # self.load_svg("/Users/hhip/Downloads/spirograph-grids/spirograph-grid.svg") def add_actions(self, toolbar: QToolBar): colorful_act = toolbar.addAction(QIcon("images/icons_colorful.png"), "Colorful") colorful_act.setCheckable(True) colorful_act.setChecked(self.plot.colorful) colorful_act.triggered.connect( lambda checked: setattr(self.plot, "colorful", checked)) show_points_act = toolbar.addAction( QIcon("images/icons_show_points.png"), "Points") show_points_act.setCheckable(True) show_points_act.setChecked(self.plot.show_points) show_points_act.triggered.connect( lambda checked: setattr(self.plot, "show_points", checked)) show_pen_up_act = toolbar.addAction( QIcon("images/icons_show_pen_up.png"), "Pen-Up") show_pen_up_act.setCheckable(True) show_pen_up_act.setChecked(self.plot.show_pen_up) show_pen_up_act.triggered.connect( lambda checked: setattr(self.plot, "show_pen_up", checked)) show_axes_act = toolbar.addAction(QIcon("images/icons_show_axes.png"), "Axes") show_axes_act.setCheckable(True) show_axes_act.setChecked(self.plot.show_axes) show_axes_act.triggered.connect( lambda checked: setattr(self.plot, "show_axes", checked)) scale = UnitComboBox() scale.setCurrentText(self.plot.unit) scale.currentTextChanged.connect( lambda text: setattr(self.plot, "unit", text)) toolbar.addWidget(scale) def load_svg(self, path: str): # TODO: make quantization a parameters vd = vpype.read_multilayer_svg(path, 0.05) self.set_vector_data(vd) def plot_svg(self): vd = vpype.VectorData() for lid in self.vector_data.layers: if self.plot.layer_visible(lid): vd.add(self.vector_data.layers[lid], 1) svg = io.StringIO() vpype.write_svg(svg, vd, page_format=self.plot.page_format) axy.plot_svg(svg.getvalue()) def set_vector_data(self, vector_data: vpype.VectorData): self.base_vector_data = vector_data self.update_view() model = QStandardItemModel() for lid in vector_data.layers: item = QStandardItem() item.setCheckable(True) item.setCheckState( Qt.Checked if self.plot.layer_visible(lid) else Qt.Unchecked) pixmap = QPixmap(16, 12) pixmap.fill(QColor(*[c * 255 for c in self.plot.layer_color(lid)])) item.setIcon(QIcon(pixmap)) item.setText(f"Layer {lid}") item.setSelectable(False) item.setEditable(False) item.setData(lid, Qt.UserRole + 1) model.appendRow(item) model.itemChanged.connect(lambda it: self.plot.set_layer_visible( it.data(Qt.UserRole + 1), it.checkState() == Qt.Checked)) self.list.setModel(model) def set_page_format(self, page_format: str): self.page_format = page_format self.settings.setValue("page_format", page_format) self.update_view() def set_landscape(self, landscape: bool): self.landscape = landscape self.settings.setValue("landscape", landscape) self.update_view() def set_rotated(self, rotated: bool): self.rotated = rotated self.settings.setValue("rotated", rotated) self.update_view() def set_center(self, center: bool): self.center = center self.settings.setValue("center", center) self.update_view() def set_fit_page(self, fit_page: bool): self.fit_page = fit_page self.settings.setValue("fit_page", fit_page) self.update_view() def set_margin(self, value: float, unit: str): self.margin_value = value self.margin_unit = unit self.settings.setValue("margin_value", value) self.settings.setValue("margin_unit", unit) if self.fit_page: self.update_view() def update_view(self): self.vector_data = copy.deepcopy(self.base_vector_data) # scale/center according to settings width, height = PAGE_FORMATS[str(self.page_format)] if self.landscape: width, height = height, width if self.rotated: self.vector_data.rotate(-math.pi / 2) self.vector_data.translate(0, height) bounds = self.vector_data.bounds() if bounds is not None: min_x, min_y, max_x, max_y = bounds margin = self.margin_value * vpype.convert(self.margin_unit) if self.fit_page: factor_x = (width - 2 * margin) / (max_x - min_x) factor_y = (height - 2 * margin) / (max_y - min_y) scale = min(factor_x, factor_y) self.vector_data.translate(-min_x, -min_y) self.vector_data.scale(scale) if factor_x < factor_y: self.vector_data.translate( margin, margin + (height - 2 * margin - (max_y - min_y) * scale) / 2) else: self.vector_data.translate( margin + (width - 2 * margin - (max_x - min_x) * scale) / 2, margin) elif self.center: self.vector_data.translate( (width - (max_x - min_x)) / 2 - min_x, (height - (max_y - min_y)) / 2 - min_y, ) # configure plot widget self.plot.vector_data = self.vector_data self.plot.page_format = (width, height)
class FormMidContextWidget(QtWidgets.QWidget): #定义成员变量 #定义信号 def __init__(self): super().__init__() self.__initForm() self.__loadMusicLibraryListWidgetData() self.__loadSongsNameListWidgetData() self.__loadCollectionMusicListWidgetData() def __initForm(self): self.mainLayout = QHBoxLayout() self.mainLayout.setContentsMargins(1, 1, 1, 1) self.contextFrame = QtWidgets.QFrame() self.contextFrame.setObjectName("contextFrame") self.midContextLayout = QHBoxLayout() self.midContextLayout.setSpacing(1) self.midContextLayout.setContentsMargins(0, 1, 0, 1) self.midLeftFrame = QtWidgets.QFrame() self.midLeftFrame.setObjectName("midLeftFrame") self.midLeftLayout = QVBoxLayout() self.midLeftFrame.setLayout(self.midLeftLayout) self.midLeftLayout.setSpacing(0) self.midLeftLayout.setContentsMargins(2, 2, 2, 2) self.musicLibraryTitleLabel = QLabel("音乐库") self.textFont = QFont("微软雅黑", 11) self.textFont.setBold(True) self.musicLibraryTitleLabel.setFont(self.textFont) self.musicLibraryListView = QListView() self.musicLibraryListView.setFixedHeight(140) self.musicLibraryListView.setObjectName('musicLibraryListView') self.musicLibraryListView.setFixedWidth(190) self.localCollectionTitleLabel = QLabel("本地收藏") self.localCollectionTitleLabel.setFont(self.textFont) self.localCollectionListView = QListView() self.localCollectionListView.setObjectName('localCollectionListView') self.localCollectionListView.setFixedWidth(190) self.songsNameListTitleLabel = QLabel("歌单列表") self.songsNameListTitleLabel.setFont(self.textFont) self.songsNameListView = QListView() self.songsNameListView.setObjectName('songsNameListView') self.songsNameListView.setFixedWidth(190) self.songsNameListView.setFixedHeight(300) self.midLeftLayout.addWidget(self.musicLibraryTitleLabel) self.midLeftLayout.addWidget(self.musicLibraryListView) self.midLeftLayout.addWidget(self.songsNameListTitleLabel) self.midLeftLayout.addWidget(self.songsNameListView) self.midLeftLayout.addWidget(self.localCollectionTitleLabel) self.midLeftLayout.addWidget(self.localCollectionListView) self.rightContextStackWidget = QStackedWidget() self.testLabel = QLabel() self.testLabel.setScaledContents(True) self.testLabel.setPixmap( QPixmap(":/icon/Resources/icon/icon-meinv.jpg").scaled( self.testLabel.width(), self.testLabel.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation)) self.rightContextStackWidget.addWidget(self.testLabel) self.midContextLayout.addWidget(self.midLeftFrame) self.midContextLayout.addWidget(self.rightContextStackWidget) self.midContextLayout.setStretch(0, 0) self.midContextLayout.setStretch(1, 1) self.contextFrame.setLayout(self.midContextLayout) self.mainLayout.addWidget(self.contextFrame) self.setLayout(self.mainLayout) def __loadMusicLibraryListWidgetData(self): self.textFont = QFont("微软雅黑", 11) self.localMusicItemData = QStandardItem("本地音乐") self.localMusicItemData.setFont(self.textFont) self.localMusicItemData.setEditable(False) self.localMusicItemData.setData( QIcon(":/icon/Resources/icon/icon-localmusic.svg"), Qt.DecorationRole) self.wangyiYunItemData = QStandardItem("网易云音乐") self.wangyiYunItemData.setFont(self.textFont) self.wangyiYunItemData.setEditable(False) self.wangyiYunItemData.setData( QIcon(":/icon/Resources/icon/icon-wangyiyunmusic.svg"), Qt.DecorationRole) self.qqMusicItemData = QStandardItem("QQ音乐") self.qqMusicItemData.setFont(self.textFont) self.qqMusicItemData.setEditable(False) self.qqMusicItemData.setData( QIcon(":/icon/Resources/icon/icon-qqmusic.svg"), Qt.DecorationRole) self.xiaMiItemData = QStandardItem("虾米音乐") self.xiaMiItemData.setFont(self.textFont) self.xiaMiItemData.setEditable(False) self.xiaMiItemData.setData( QIcon(":/icon/Resources/icon/icon-xiamimusic.svg"), Qt.DecorationRole) self.musicLibraryModel = QStandardItemModel() self.musicLibraryModel.appendRow(self.localMusicItemData) self.musicLibraryModel.appendRow(self.wangyiYunItemData) self.musicLibraryModel.appendRow(self.qqMusicItemData) self.musicLibraryModel.appendRow(self.xiaMiItemData) self.musicLibraryListView.setSpacing(2) self.musicLibraryListView.setModel(self.musicLibraryModel) def __loadSongsNameListWidgetData(self): self.wubaiItemData = QStandardItem("伍佰&China blue") self.textFont = QFont("微软雅黑", 11) self.wubaiItemData.setFont(self.textFont) self.wubaiItemData.setEditable(False) self.wubaiItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.zongguanxianItemData = QStandardItem("纵贯线") self.zongguanxianItemData.setFont(self.textFont) self.zongguanxianItemData.setEditable(False) self.zongguanxianItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.zhaoleiItemData = QStandardItem("赵雷专辑") self.zhaoleiItemData.setFont(self.textFont) self.zhaoleiItemData.setEditable(False) self.zhaoleiItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.xuweiItemData = QStandardItem("许巍专辑") self.xuweiItemData.setFont(self.textFont) self.xuweiItemData.setEditable(False) self.xuweiItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.zhouhuajianItemData = QStandardItem("周华健专辑") self.zhouhuajianItemData.setFont(self.textFont) self.zhouhuajianItemData.setEditable(False) self.zhouhuajianItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.banderuiItemData = QStandardItem("班得瑞专辑") self.banderuiItemData.setFont(self.textFont) self.banderuiItemData.setEditable(False) self.banderuiItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.yaogunItemData = QStandardItem("摇滚专辑") self.yaogunItemData.setFont(self.textFont) self.yaogunItemData.setEditable(False) self.yaogunItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.yinshiyuanshenItemData = QStandardItem("影视原声") self.yinshiyuanshenItemData.setFont(self.textFont) self.yinshiyuanshenItemData.setEditable(False) self.yinshiyuanshenItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.minyaoItemData = QStandardItem("民谣专辑") self.minyaoItemData.setFont(self.textFont) self.minyaoItemData.setEditable(False) self.minyaoItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.tianlaizhiyinItemData = QStandardItem("天籁之音") self.tianlaizhiyinItemData.setFont(self.textFont) self.tianlaizhiyinItemData.setEditable(False) self.tianlaizhiyinItemData.setData( QIcon(":/icon/Resources/icon/icon-gedanlist.svg"), Qt.DecorationRole) self.songsNameListModel = QStandardItemModel() self.songsNameListModel.appendRow(self.wubaiItemData) self.songsNameListModel.appendRow(self.zongguanxianItemData) self.songsNameListModel.appendRow(self.zhaoleiItemData) self.songsNameListModel.appendRow(self.xuweiItemData) self.songsNameListModel.appendRow(self.zhouhuajianItemData) self.songsNameListModel.appendRow(self.banderuiItemData) self.songsNameListModel.appendRow(self.yaogunItemData) self.songsNameListModel.appendRow(self.yinshiyuanshenItemData) self.songsNameListModel.appendRow(self.minyaoItemData) self.songsNameListModel.appendRow(self.tianlaizhiyinItemData) self.songsNameListView.setSpacing(2) self.songsNameListView.setModel(self.songsNameListModel) def __loadCollectionMusicListWidgetData(self): self.jingdianItemData = QStandardItem("经典老歌") self.textFont = QFont("微软雅黑", 11) self.jingdianItemData.setFont(self.textFont) self.jingdianItemData.setEditable(False) self.jingdianItemData.setData( QIcon(":/icon/Resources/icon/icon-collectionmusic.svg"), Qt.DecorationRole) self.qinyinyueItemData = QStandardItem("轻音乐系") self.qinyinyueItemData.setFont(self.textFont) self.qinyinyueItemData.setEditable(False) self.qinyinyueItemData.setData( QIcon(":/icon/Resources/icon/icon-collectionmusic.svg"), Qt.DecorationRole) self.jitaxilieItemData = QStandardItem("吉他系列") self.jitaxilieItemData.setFont(self.textFont) self.jitaxilieItemData.setEditable(False) self.jitaxilieItemData.setData( QIcon(":/icon/Resources/icon/icon-collectionmusic.svg"), Qt.DecorationRole) self.remengequItemData = QStandardItem("热门歌曲") self.remengequItemData.setFont(self.textFont) self.remengequItemData.setEditable(False) self.remengequItemData.setData( QIcon(":/icon/Resources/icon/icon-collectionmusic.svg"), Qt.DecorationRole) self.songsNameModel = QStandardItemModel() self.songsNameModel.appendRow(self.jingdianItemData) self.songsNameModel.appendRow(self.qinyinyueItemData) self.songsNameModel.appendRow(self.jitaxilieItemData) self.songsNameModel.appendRow(self.remengequItemData) self.localCollectionListView.setSpacing(2) self.localCollectionListView.setModel(self.songsNameModel)