Esempio n. 1
0
 def createPopupMenu(self) -> QtWidgets.QMenu:
     menu = super().createPopupMenu()
     menu.clear()
     toolbars: typing.Sequence[QtWidgets.QToolBar] = gg(self.findChildren(QtWidgets.QToolBar))
     for clazz in self._toolbarClasses:
         assert issubclass(clazz, ToolbarMixin)
         toolbar = next((x for x in toolbars if isinstance(x, clazz)), None)
         action = menu.addAction(clazz.getToolbarTitle())
         action.setCheckable(True)
         action.setChecked(toolbar is not None)
         action.triggered.connect(lambda clazz=clazz, toolbar=toolbar: self.addToolBar(
             clazz(self)) if toolbar is None else self.removeToolBar(toolbar))
     menu.addSeparator()
     for toolbar in toolbars:
         if toolbar.rect().contains(toolbar.mapFromGlobal(QtGui.QCursor.pos())):
             title = tt.Toolbar_Lock % gg(toolbar).getToolbarTitle()
             action = QtWidgets.QAction(title, menu)
             action.setCheckable(True)
             action.setChecked(not toolbar.isMovable())
             action.triggered.connect(lambda *args, toolbar=toolbar: toolbar.setMovable(not toolbar.isMovable()))
             menu.addAction(action)
     menu.addSeparator()
     lockAllAction = QtWidgets.QAction(tt.Toolbar_LockAll, menu)
     lockAllAction.setDisabled(all(not x.isMovable() for x in toolbars))
     lockAllAction.triggered.connect(lambda: list(x.setMovable(False) for x in toolbars))
     unlockAllAction = QtWidgets.QAction(tt.Toolbar_UnlockAll, menu)
     unlockAllAction.setDisabled(all(x.isMovable() for x in toolbars))
     unlockAllAction.triggered.connect(lambda: list(x.setMovable(True) for x in toolbars))
     menu.addAction(lockAllAction)
     menu.addAction(unlockAllAction)
     return menu
Esempio n. 2
0
 def __init__(self,
              parent: typing.Optional[QtWidgets.QWidget] = None) -> None:
     super().__init__(parent)
     self.setSelectionBehavior(
         QtWidgets.QTableView.SelectionBehavior.SelectRows)
     self.setEditTriggers(
         gg(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers,
            QtWidgets.QAbstractItemView.EditTriggers))
     self.horizontalHeader().setStretchLastSection(True)
     self.horizontalHeader().setDefaultAlignment(
         gg(QtCore.Qt.AlignmentFlag.AlignLeft)
         | QtCore.Qt.AlignmentFlag.AlignVCenter)
     self.setAlternatingRowColors(True)
     self.setStyleSheet("alternate-background-color: rgb(245, 245, 245)")
     self.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
     self.setShowGrid(False)
     self.setItemDelegate(self.NoFocusDelegate())
     self.horizontalHeader().setStyleSheet(
         "QHeaderView::section { border-top:0px solid #D8D8D8; border-bottom: 1px solid #D8D8D8; "
         "background-color:white; padding:2px; font-weight: light; }")
     self.horizontalHeader().setHighlightSections(False)
     tablePalette = self.palette()
     tablePalette.setColor(
         QtGui.QPalette.ColorGroup.Inactive,
         QtGui.QPalette.ColorRole.Highlight,
         tablePalette.color(QtGui.QPalette.ColorGroup.Active,
                            QtGui.QPalette.ColorRole.Highlight))
     tablePalette.setColor(
         QtGui.QPalette.ColorGroup.Inactive,
         QtGui.QPalette.ColorRole.HighlightedText,
         tablePalette.color(QtGui.QPalette.ColorGroup.Active,
                            QtGui.QPalette.ColorRole.HighlightedText))
     self.setPalette(tablePalette)
    def __init__(self, target: ControlsWidget):
        super().__init__()
        self._target = target
        self._widgetConfig = target.getWidgetConfig()
        self._logger = logging.getLogger("controlsWidgetConfig")
        sizes = [16, 24, 32, 40, 48, 64, 96, 128]
        layout = QtWidgets.QGridLayout()
        self._iconSizeLabel = QtWidgets.QLabel(tt.ControlsWidget_IconSize)
        self._iconSizeCombo = QtWidgets.QComboBox()
        self._iconSizeCombo.addItems([str(x) for x in sizes])
        self._iconSizeCombo.setCurrentIndex(
            sizes.index(self._widgetConfig.iconSize))
        self._buttonBox = QtWidgets.QDialogButtonBox(
            gg(QtWidgets.QDialogButtonBox.Ok)
            | gg(QtWidgets.QDialogButtonBox.Cancel)
            | gg(QtWidgets.QDialogButtonBox.Apply))

        layout.setColumnStretch(0, 1)
        layout.setColumnStretch(1, 2)
        layout.addWidget(self._iconSizeLabel)
        layout.addWidget(self._iconSizeCombo)
        layout.addWidget(WidgetUtils.createExpandingSpacer(),
                         layout.rowCount(), 0, 1, 2)
        layout.addWidget(self._buttonBox, layout.rowCount(), 0, 1, 2)
        self.setLayout(layout)
        self._buttonBox.clicked.connect(self._onButtonBoxClicked)
Esempio n. 4
0
 def _loadConfig(self):
     screenSize = QtGui.QGuiApplication.primaryScreen().size()
     windowSize = gg(screenSize) / 1.5
     diffSize = (screenSize - windowSize) / 2
     defaultGeometry = QtCore.QRect(QtCore.QPoint(diffSize.width(), diffSize.height()), windowSize)
     self.setGeometry(defaultGeometry)
     self._loadToolbars(self._config.toolbars)
     self.restoreGeometry(QtCore.QByteArray(gg(self._config.geometry)))
     self.restoreState(QtCore.QByteArray(gg(self._config.state)))
Esempio n. 5
0
 def _onLayoutEditingChanged(self, editing: bool) -> None:
     if editing:
         self._logger.info("Create mask widget")
         self._maskWidget = MaskWidget(self)
         self._maskWidget.show()
     else:
         self._maskWidget.setParent(gg(None))
         self._maskWidget = None
     self._logger.info("Refresh splitter handles")
     for widget in self.findChildren(SplitterWidget):
         gg(widget, SplitterWidget).refreshHandles()
Esempio n. 6
0
 def _setupLyrics(self):
     self._logger.info(">> Setting up lyrics...")
     if self._player.getCurrentMusic().isAbsent():
         self._logger.info("No music, return")
         return
     currentMusic = self._player.getCurrentMusic().orElseThrow(AssertionError)
     lyricsPath = Path(currentMusic.filename).with_suffix(".lrc")
     lyricsText = lyricsPath.read_text(encoding="gbk")
     self._logger.info("Parsing lyrics")
     lyrics = LyricUtils.parseLyrics(lyricsText)
     self._logger.info("Lyrics count: %d", len(lyrics))
     self._lyrics = lyrics
     self._prevLyricIndex = -1
     LayoutUtils.clearLayout(self._layout)
     self._layout.addSpacing(self.height() // 2)
     for position, lyric in list(lyrics.items())[:]:
         lyricLabel = ClickableLabel(lyric, self)
         lyricLabel.setAlignment(
             gg(QtCore.Qt.AlignmentFlag.AlignCenter, Any) | QtCore.Qt.AlignmentFlag.AlignVCenter)
         lyricLabel.clicked.connect(
             lambda _, position=position: self._player.setPosition(position))
         lyricLabel.setMargin(int(2 * self._app.getZoom()))
         self._layout.addWidget(lyricLabel)
     self._layout.addSpacing(self.height() // 2)
     self._logger.info("Lyrics layout has children: %d", self._layout.count())
     self.verticalScrollBar().setValue(0)
     self._logger.info("<< Lyrics set up")
Esempio n. 7
0
 def paint(self, painter: QtGui.QPainter,
           option: QtWidgets.QStyleOptionViewItem,
           index: QtCore.QModelIndex) -> None:
     itemOption = QtWidgets.QStyleOptionViewItem(option)
     if gg(option, typing.Any).state & QtWidgets.QStyle.State_HasFocus:
         itemOption.state = itemOption.state ^ QtWidgets.QStyle.State_HasFocus
     super().paint(painter, itemOption, index)
Esempio n. 8
0
 def loadLayout(self, layout: Element) -> None:
     self._logger.info("Load layout")
     if self.centralWidget() is not None:
         self._logger.info("Central widget is not none, clear it")
         self.centralWidget().setParent(gg(None))
         assert self.centralWidget() is None
     self._drawElement(layout, self)
Esempio n. 9
0
 def _selectRows(self, indexes: typing.Iterable[int]) -> None:
     for index in indexes:
         self.selectionModel().select(
             QtCore.QItemSelection(self.model().index(index, 0),
                                   self.model().index(index, 2)),
             gg(QtCore.QItemSelectionModel.Select, typing.Any)
             | QtCore.QItemSelectionModel.Rows)
Esempio n. 10
0
 def _setLyricIndex(self, lyricIndex):
     self._logger.debug("Set lyric index to %d", lyricIndex)
     for index in range(len(self._lyrics)):
         lyricLabel: QtWidgets.QLabel = gg(self._layout.itemAt(index + 1).widget())
         color = QtGui.QColor("#e1413c" if index == lyricIndex else "#23557d")
         palette = lyricLabel.palette()
         palette.setColor(QtGui.QPalette.ColorRole.WindowText, color)
         lyricLabel.setPalette(palette)
         originalValue = self.verticalScrollBar().value()
         targetValue = lyricLabel.pos().y() - self.height() // 2 + lyricLabel.height() // 2
         index == lyricIndex and (lambda animation=QtCore.QPropertyAnimation(
             self.verticalScrollBar(), gg(b"value"), self): [
             animation.setStartValue(originalValue),
             animation.setEndValue(targetValue),
             animation.start(QtCore.QPropertyAnimation.DeletionPolicy.DeleteWhenStopped)
         ])()
     self._logger.debug("Lyrics refreshed")
Esempio n. 11
0
 def __init__(self):
     super().__init__()
     self._app = App.instance()
     self.setLayout(QtWidgets.QGridLayout(self))
     self._label = QtWidgets.QLabel()
     self._label.setAlignment(gg(QtCore.Qt.AlignmentFlag.AlignCenter))
     self.layout().addWidget(self._label)
     self._refreshView()
     self._app.languageChanged.connect(self._refreshView)
Esempio n. 12
0
 def createButtonBox(ok=False, cancel=False, apply=False):
     flag = 0
     if ok:
         flag |= QtWidgets.QDialogButtonBox.StandardButton.Ok
     if cancel:
         flag |= QtWidgets.QDialogButtonBox.StandardButton.Cancel
     if apply:
         flag |= QtWidgets.QDialogButtonBox.StandardButton.Apply
     return QtWidgets.QDialogButtonBox(gg(flag))
 def __init__(self, target: DemoWidget) -> None:
     super().__init__()
     self._target = target
     self._logger = logging.getLogger("demoWidgetConfigWidget")
     self._widgetConfig = target.getWidgetConfig()
     increaseButton = QtWidgets.QPushButton("Increase")
     decreaseButton = QtWidgets.QPushButton("Decrease")
     self._widgetCounterLabel = QtWidgets.QLabel()
     layout = QtWidgets.QVBoxLayout()
     layout.setSpacing(15)
     layout.addStretch()
     layout.addWidget(decreaseButton, 0, gg(QtCore.Qt.AlignCenter))
     layout.addWidget(self._widgetCounterLabel, 0,
                      gg(QtCore.Qt.AlignCenter))
     layout.addWidget(increaseButton, 0, gg(QtCore.Qt.AlignCenter))
     layout.addStretch()
     self.setLayout(layout)
     increaseButton.clicked.connect(self._onIncreaseButtonClicked)
     decreaseButton.clicked.connect(self._onDecreaseButtonClicked)
     target.widgetConfigChanged.connect(self._onWidgetConfigChanged)
     self._refreshWidget()
Esempio n. 14
0
 def __init__(self, config=None):
     super().__init__()
     self._logger = logging.getLogger("demoWidget")
     self._app = App.instance()
     self._pluginConfig = DemoPlugin.getPluginConfig()
     self._widgetConfig = config or self.getWidgetConfigClass().getDefaultObject()
     self._pluginCounterLabel = QtWidgets.QLabel()
     self._widgetCounterLabel = QtWidgets.QLabel()
     layout = QtWidgets.QVBoxLayout()
     layout.setSpacing(15)
     layout.addStretch()
     layout.addWidget(self._pluginCounterLabel, 0, gg(QtCore.Qt.AlignCenter))
     layout.addWidget(self._widgetCounterLabel, 0, gg(QtCore.Qt.AlignCenter))
     layout.addStretch()
     self.setLayout(layout)
     DemoPlugin.pluginConfigChanged.connect(self._onPluginConfigChanged)
     self.widgetConfigChanged.connect(self._onWidgetConfigChanged)
     self._app.languageChanged.connect(self.onLanguageChanged)
     self.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
     self.customContextMenuRequested.connect(self._onCustomContextMenuRequested)
     self._refreshWidget()
Esempio n. 15
0
 def __init__(self) -> None:
     super().__init__()
     self._app = App.instance()
     self._logger = logging.getLogger("demoPluginConfigWidget")
     self._pluginConfig = DemoPlugin.getPluginConfig()
     decreaseButton = QtWidgets.QPushButton("Decrease")
     increaseButton = QtWidgets.QPushButton("Increase")
     self._pluginCounterLabel = QtWidgets.QLabel()
     layout = QtWidgets.QVBoxLayout()
     layout.setSpacing(15)
     layout.addStretch()
     layout.addWidget(decreaseButton, 0, gg(QtCore.Qt.AlignCenter))
     layout.addWidget(self._pluginCounterLabel, 0,
                      gg(QtCore.Qt.AlignCenter))
     layout.addWidget(increaseButton, 0, gg(QtCore.Qt.AlignCenter))
     layout.addStretch()
     self.setLayout(layout)
     increaseButton.clicked.connect(self._onIncreaseButtonClicked)
     decreaseButton.clicked.connect(self._onDecreaseButtonClicked)
     DemoPlugin.pluginConfigChanged.connect(self._onPluginConfigChanged)
     self._app.languageChanged.connect(self._onLanguageChanged)
     self._refreshWidget()
Esempio n. 16
0
 def _doReplace(self, widget: ReplacerMixin):
     assert isinstance(widget, QtWidgets.QWidget)
     logger = logging.getLogger("maskWidget")
     parent = self._replaceable.parentWidget()
     logger.info("Replacing %s with %s", self._replaceable, widget)
     assert isinstance(widget, (QtWidgets.QWidget, ReplacerMixin))
     if isinstance(parent, QtWidgets.QMainWindow):
         logger.info("Parent is main window")
         parent.setCentralWidget(widget)
     elif isinstance(parent, QtWidgets.QSplitter):
         logger.info("Parent is splitter")
         parent.replaceWidget(parent.indexOf(self._replaceable), widget)
     else:
         logger.info("Parent is others")
         parent.layout().replaceWidget(self._replaceable, widget)
     self._replaceable.setParent(gg(None))
     self.raise_()
     self._app.getMainWindow().layoutChanged.emit()
Esempio n. 17
0
 def _loadElementConfig(self, element: Element):
     from IceSpringMusicPlayer.common.pluginWidgetMixin import PluginWidgetMixin
     if issubclass(element.clazz, PluginWidgetMixin):
         self._logger.info("Load element config: %s", element)
         elementConfigJd = json.loads(json.dumps(
             element.config,
             default=element.clazz.getWidgetConfigClass().pythonToJson),
                                      object_pairs_hook=element.clazz.
                                      getWidgetConfigClass().jsonToPython)
         elementConfig = gg(
             element.clazz.getWidgetConfigClass(
             ))(**
                {
                    **element.clazz.getWidgetConfigClass().getDefaultObject(
                    ).__dict__,
                    **elementConfigJd
                })
         self._logger.info("Loaded element config: %s", elementConfig)
         element.config = elementConfig
     for child in element.children:
         self._loadElementConfig(child)
Esempio n. 18
0
 def _drawElement(self, element: Element, parent: QtWidgets.QWidget) -> None:
     self._logger.info("Draw element: %s to %s", element.clazz, parent)
     if issubclass(element.clazz, PluginWidgetMixin) and "config" in inspect.signature(
             element.clazz.__init__).parameters.keys():
         widget = gg(element.clazz)(element.config)
     else:
         widget = element.clazz()
     if isinstance(widget, QtWidgets.QSplitter) and element.vertical:
         widget.setOrientation(QtCore.Qt.Orientation.Vertical)
     if isinstance(parent, QtWidgets.QMainWindow):
         self._logger.info("Parent is main window")
         parent.setCentralWidget(widget)
     elif isinstance(parent, QtWidgets.QSplitter):
         self._logger.info("Parent is splitter")
         parent.addWidget(widget)
         parent.setProperty("iceSizes", (parent.property("iceSizes") or ()) + (element.weight * 2 ** 16,))
         parent.setSizes(parent.property("iceSizes"))
     else:
         raise AssertionError("Unsupported parent: %s" % type(parent))
     for child in element.children:
         self._drawElement(child, widget)
Esempio n. 19
0
 def _loadConfig(self) -> Config:
     self._logger.info("Load config")
     path = Path("config.json")
     if not path.exists():
         self._logger.info("No config.json file, return default config")
         return self.getDefaultConfig()
     jd = json.loads(path.read_text(), object_pairs_hook=Config.fromJson)
     config = Config(
         **{
             **self.getDefaultConfig().__dict__,
             **{k: v
                for k, v in jd.items() if k in Config.__annotations__}
         })
     self._logger.info("Process plugin configs (%d plugins)",
                       len(self._pluginService.getPluginClasses()))
     for plugin in config.plugins:
         self._logger.info("Plugin in config: %s", plugin)
         jd = json.loads(json.dumps(
             plugin.config,
             default=plugin.clazz.getPluginConfigClass().pythonToJson),
                         object_pairs_hook=plugin.clazz.
                         getPluginConfigClass().jsonToPython)
         plugin.config = gg(plugin.clazz.getPluginConfigClass())(**jd)
     self._logger.info("Process plugins not in config")
     loadedClasses = [x.clazz for x in config.plugins]
     for clazz in self._pluginService.getPluginClasses():
         if clazz not in loadedClasses:
             self._logger.info("Plugin not in config: %s", clazz)
             config.plugins.append(
                 Plugin(clazz=clazz,
                        disabled=False,
                        config=clazz.getPluginConfigClass().
                        getDefaultObject()))
     self._logger.info("Sort plugins")
     config.plugins.sort(
         key=lambda x: x.clazz.__module__ + "." + x.clazz.__name__)
     self._logger.info("Load layout config")
     self._loadElementConfig(config.layout)
     self._logger.info("Loaded config: %s", config)
     return config
Esempio n. 20
0
 def __init__(self, config, parent) -> None:
     super().__init__()
     self._widgetConfig = config
     self._parent = gg(parent)
     self._logger = logging.getLogger("playlistTable")
     self._app = App.instance()
     self._player = App.instance().getPlayer()
     self._playlistService = self._app.getPlaylistService()
     self.setModel(PlaylistModel(self))
     self.setColumnWidth(0, int(35 * self._app.getZoom()))
     self.setColumnWidth(1, int(150 * self._app.getZoom()))
     self.doubleClicked.connect(self._onDoubleClicked)
     self.setIconSize(QtCore.QSize(32, 32) * self._app.getZoom())
     self.horizontalHeader().setSortIndicator(
         -1, QtCore.Qt.SortOrder.AscendingOrder)
     self.setWordWrap(False)
     self.setSortingEnabled(True)
     self.setContextMenuPolicy(
         QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
     self.customContextMenuRequested.connect(
         self._onCustomContextMenuRequested)
     self.selectionModel().selectionChanged.connect(
         self._onSelectionChanged)
     self._app.requestLocateCurrentMusic.connect(
         self._onRequestLocateCurrentMusic)
     self._player.stateChanged.connect(self._onPlayerStateChanged)
     self._player.frontPlaylistIndexAboutToBeChanged.connect(
         self._onFrontPlaylistIndexAboutToBeChanged)
     self._player.frontPlaylistIndexChanged.connect(
         self._onFrontPlaylistIndexChanged)
     self._player.selectedMusicIndexesChanged.connect(
         self._onSelectedMusicIndexesChanged)
     self._player.currentMusicIndexChanged.connect(
         self._onCurrentMusicIndexChanged)
     self._player.musicsInserted.connect(self._onMusicsInserted)
     self._player.musicsRemoved.connect(self._onMusicsRemoved)
     self._player.musicsSorted.connect(self._onMusicsSorted)
     self._selectAndFollowMusics(self._player.getSelectedMusicIndexes())
     self._loadConfig()
     self._parent.widgetConfigChanged.connect(self._onWidgetConfigChanged)
Esempio n. 21
0
 def toggleFullscreen(cls, widget: QtWidgets.QWidget):
     if not hasattr(cls, "__fullscreen"):
         setattr(cls, "__fullscreen", dict())
     jd = getattr(cls, "__fullscreen")
     if not widget.isFullScreen():
         parent = widget.parentWidget()
         window = QApplication.activeWindow()
         assert isinstance(parent, QtWidgets.QSplitter)
         jd[id(widget)] = [
             parent,
             parent.indexOf(widget),
             parent.sizes(),
             QApplication.activeWindow()
         ]
         widget.setParent(gg(None))
         widget.showFullScreen()
         window.hide()
     else:
         parent, index, sizes, window = jd[id(widget)]
         assert isinstance(parent, QtWidgets.QSplitter)
         window.show()
         parent.insertWidget(index, widget)
         parent.setSizes(sizes)
         del jd[id(widget)]
Esempio n. 22
0
 def model(self) -> PlaylistManagerModel:
     return gg(super().model())
Esempio n. 23
0
 def __init__(self):
     super().__init__()
     label = QtWidgets.QLabel("Hello World")
     label.setAlignment(gg(QtCore.Qt.AlignmentFlag.AlignCenter))
     self.setLayout(QtWidgets.QGridLayout())
     self.layout().addWidget(label)
Esempio n. 24
0
 def createExpandingSpacer():
     spacer = QtWidgets.QWidget()
     spacer.setSizePolicy(gg(QtWidgets.QSizePolicy.Expanding),
                          gg(QtWidgets.QSizePolicy.Expanding))
     return spacer
Esempio n. 25
0
 def clearLayout(layout: QtWidgets.QLayout):
     for i in reversed(range(layout.count())):
         layout.itemAt(i).widget().setParent(gg(None, QtCore.QObject)) if layout.itemAt(i).widget() \
             else layout.removeItem(layout.itemAt(i))
Esempio n. 26
0
 def _clearAndSelectRow(self, index: int) -> None:
     self.selectionModel().select(
         self.model().index(index, 0),
         gg(QtCore.QItemSelectionModel.SelectionFlag.ClearAndSelect,
            typing.Any) | QtCore.QItemSelectionModel.SelectionFlag.Rows)
Esempio n. 27
0
 def instance() -> App:
     return gg(QtCore.QCoreApplication.instance())
Esempio n. 28
0
 def _selectRowRange(self, fromRow, toRow):
     self.selectionModel().select(
         QtCore.QItemSelection(self.model().index(fromRow, 0),
                               self.model().index(toRow, 0)),
         gg(QtCore.QItemSelectionModel.Select, typing.Any)
         | QtCore.QItemSelectionModel.Rows)
Esempio n. 29
0
 def model(self) -> "PlaylistModel":
     return gg(super().model())
Esempio n. 30
0
 def _widgetToElement(self, widget: QtWidgets.QWidget) -> Element:
     from IceSpringMusicPlayer.common.replacerMixin import ReplacerMixin
     assert isinstance(widget, (ReplacerMixin, QtWidgets.QWidget))
     return Element(
         clazz=type(widget),
         vertical=isinstance(widget, QtWidgets.QSplitter) and widget.orientation() == QtCore.Qt.Orientation.Vertical,
         weight=widget.height() if isinstance(widget.parentWidget(), QtWidgets.QSplitter) and gg(
             widget.parentWidget()).orientation() == QtCore.Qt.Orientation.Vertical else widget.width(),
         config=widget.getWidgetConfig() if isinstance(widget, PluginWidgetMixin) else dict(),
         children=[self._widgetToElement(widget.widget(x)) for x in range(widget.count())] if isinstance(
             widget, SplitterWidget) else []
     )