Compare commits
3 Commits
87a0b0149c
...
955bea2037
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
955bea2037 | ||
|
|
5ed7b822e1 | ||
|
|
b40c81e79a |
@ -14,6 +14,11 @@ from PyQt6.QtCore import (
|
|||||||
pyqtSignal,
|
pyqtSignal,
|
||||||
QObject,
|
QObject,
|
||||||
)
|
)
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QProxyStyle,
|
||||||
|
QStyle,
|
||||||
|
QStyleOption,
|
||||||
|
)
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
|
|
||||||
@ -31,6 +36,14 @@ class Col(Enum):
|
|||||||
NOTE = auto()
|
NOTE = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class QueryCol(Enum):
|
||||||
|
TITLE = 0
|
||||||
|
ARTIST = auto()
|
||||||
|
DURATION = auto()
|
||||||
|
LAST_PLAYED = auto()
|
||||||
|
BITRATE = auto()
|
||||||
|
|
||||||
|
|
||||||
def singleton(cls):
|
def singleton(cls):
|
||||||
"""
|
"""
|
||||||
Make a class a Singleton class (see
|
Make a class a Singleton class (see
|
||||||
@ -100,6 +113,24 @@ class MusicMusterSignals(QObject):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
|
||||||
|
class PlaylistStyle(QProxyStyle):
|
||||||
|
def drawPrimitive(self, element, option, painter, widget=None):
|
||||||
|
"""
|
||||||
|
Draw a line across the entire row rather than just the column
|
||||||
|
we're hovering over.
|
||||||
|
"""
|
||||||
|
if (
|
||||||
|
element == QStyle.PrimitiveElement.PE_IndicatorItemViewItemDrop
|
||||||
|
and not option.rect.isNull()
|
||||||
|
):
|
||||||
|
option_new = QStyleOption(option)
|
||||||
|
option_new.rect.setLeft(0)
|
||||||
|
if widget:
|
||||||
|
option_new.rect.setRight(widget.width())
|
||||||
|
option = option_new
|
||||||
|
super().drawPrimitive(element, option, painter, widget)
|
||||||
|
|
||||||
|
|
||||||
class Tags(NamedTuple):
|
class Tags(NamedTuple):
|
||||||
artist: str = ""
|
artist: str = ""
|
||||||
title: str = ""
|
title: str = ""
|
||||||
|
|||||||
@ -31,6 +31,7 @@ class Config(object):
|
|||||||
COLOUR_NORMAL_TAB = "#000000"
|
COLOUR_NORMAL_TAB = "#000000"
|
||||||
COLOUR_NOTES_PLAYLIST = "#b8daff"
|
COLOUR_NOTES_PLAYLIST = "#b8daff"
|
||||||
COLOUR_ODD_PLAYLIST = "#f2f2f2"
|
COLOUR_ODD_PLAYLIST = "#f2f2f2"
|
||||||
|
COLOUR_QUERYLIST_SELECTED = "#d3ffd3"
|
||||||
COLOUR_UNREADABLE = "#dc3545"
|
COLOUR_UNREADABLE = "#dc3545"
|
||||||
COLOUR_WARNING_TIMER = "#ffc107"
|
COLOUR_WARNING_TIMER = "#ffc107"
|
||||||
DBFS_SILENCE = -50
|
DBFS_SILENCE = -50
|
||||||
@ -79,6 +80,7 @@ class Config(object):
|
|||||||
MAIL_SERVER = os.environ.get("MAIL_SERVER") or "woodlands.midnighthax.com"
|
MAIL_SERVER = os.environ.get("MAIL_SERVER") or "woodlands.midnighthax.com"
|
||||||
MAIL_USERNAME = os.environ.get("MAIL_USERNAME")
|
MAIL_USERNAME = os.environ.get("MAIL_USERNAME")
|
||||||
MAIL_USE_TLS = os.environ.get("MAIL_USE_TLS") is not None
|
MAIL_USE_TLS = os.environ.get("MAIL_USE_TLS") is not None
|
||||||
|
MAIN_WINDOW_TITLE = "MusicMuster"
|
||||||
MAX_IMPORT_MATCHES = 5
|
MAX_IMPORT_MATCHES = 5
|
||||||
MAX_IMPORT_THREADS = 3
|
MAX_IMPORT_THREADS = 3
|
||||||
MAX_INFO_TABS = 5
|
MAX_INFO_TABS = 5
|
||||||
@ -112,7 +114,6 @@ class Config(object):
|
|||||||
TEXT_NO_TRACK_NO_NOTE = "[Section header]"
|
TEXT_NO_TRACK_NO_NOTE = "[Section header]"
|
||||||
TOD_TIME_FORMAT = "%H:%M:%S"
|
TOD_TIME_FORMAT = "%H:%M:%S"
|
||||||
TRACK_TIME_FORMAT = "%H:%M:%S"
|
TRACK_TIME_FORMAT = "%H:%M:%S"
|
||||||
USE_INTERNAL_BROWSER = False
|
|
||||||
VLC_MAIN_PLAYER_NAME = "MusicMuster Main Player"
|
VLC_MAIN_PLAYER_NAME = "MusicMuster Main Player"
|
||||||
VLC_PREVIEW_PLAYER_NAME = "MusicMuster Preview Player"
|
VLC_PREVIEW_PLAYER_NAME = "MusicMuster Preview Player"
|
||||||
VLC_VOLUME_DEFAULT = 75
|
VLC_VOLUME_DEFAULT = 75
|
||||||
|
|||||||
@ -18,7 +18,6 @@ class DatabaseManager:
|
|||||||
def __init__(self, database_url: str, **kwargs: dict) -> None:
|
def __init__(self, database_url: str, **kwargs: dict) -> None:
|
||||||
if DatabaseManager.__instance is None:
|
if DatabaseManager.__instance is None:
|
||||||
self.db = Alchemical(database_url, **kwargs)
|
self.db = Alchemical(database_url, **kwargs)
|
||||||
self.db.create_all()
|
|
||||||
DatabaseManager.__instance = self
|
DatabaseManager.__instance = self
|
||||||
else:
|
else:
|
||||||
raise Exception("Attempted to create a second DatabaseManager instance")
|
raise Exception("Attempted to create a second DatabaseManager instance")
|
||||||
|
|||||||
@ -50,7 +50,8 @@ class PlaydatesTable(Model):
|
|||||||
lastplayed: Mapped[dt.datetime] = mapped_column(index=True)
|
lastplayed: Mapped[dt.datetime] = mapped_column(index=True)
|
||||||
track_id: Mapped[int] = mapped_column(ForeignKey("tracks.id"))
|
track_id: Mapped[int] = mapped_column(ForeignKey("tracks.id"))
|
||||||
track: Mapped["TracksTable"] = relationship(
|
track: Mapped["TracksTable"] = relationship(
|
||||||
"TracksTable", back_populates="playdates"
|
"TracksTable",
|
||||||
|
back_populates="playdates",
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
@ -103,7 +104,7 @@ class PlaylistRowsTable(Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
playlist: Mapped[PlaylistsTable] = relationship(back_populates="rows")
|
playlist: Mapped[PlaylistsTable] = relationship(back_populates="rows")
|
||||||
track_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tracks.id"))
|
track_id: Mapped[Optional[int]] = mapped_column(ForeignKey("tracks.id", ondelete="CASCADE"))
|
||||||
track: Mapped["TracksTable"] = relationship(
|
track: Mapped["TracksTable"] = relationship(
|
||||||
"TracksTable",
|
"TracksTable",
|
||||||
back_populates="playlistrows",
|
back_populates="playlistrows",
|
||||||
@ -127,7 +128,9 @@ class QueriesTable(Model):
|
|||||||
query: Mapped[str] = mapped_column(
|
query: Mapped[str] = mapped_column(
|
||||||
String(2048), index=False, default="", nullable=False
|
String(2048), index=False, default="", nullable=False
|
||||||
)
|
)
|
||||||
playlist_id: Mapped[int] = mapped_column(ForeignKey("playlists.id"), index=True)
|
playlist_id: Mapped[int] = mapped_column(
|
||||||
|
ForeignKey("playlists.id", ondelete="CASCADE"), index=True
|
||||||
|
)
|
||||||
playlist: Mapped[PlaylistsTable] = relationship(back_populates="query")
|
playlist: Mapped[PlaylistsTable] = relationship(back_populates="query")
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
# Standard library imports
|
|
||||||
import datetime as dt
|
|
||||||
from typing import Dict, Optional
|
|
||||||
|
|
||||||
# PyQt imports
|
|
||||||
from PyQt6.QtCore import QUrl
|
|
||||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
|
||||||
from PyQt6.QtWidgets import QTabWidget, QWidget
|
|
||||||
|
|
||||||
# Third party imports
|
|
||||||
|
|
||||||
# App imports
|
|
||||||
from config import Config
|
|
||||||
|
|
||||||
|
|
||||||
class InfoTabs(QTabWidget):
|
|
||||||
"""
|
|
||||||
Class to manage info tabs
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, parent: Optional[QWidget] = None) -> None:
|
|
||||||
super().__init__(parent)
|
|
||||||
|
|
||||||
if Config.USE_INTERNAL_BROWSER:
|
|
||||||
# re-use the oldest one later)
|
|
||||||
self.last_update: Dict[QWebEngineView, dt.datetime] = {}
|
|
||||||
self.tabtitles: Dict[int, str] = {}
|
|
||||||
|
|
||||||
# Create one tab which (for some reason) creates flickering if
|
|
||||||
# done later
|
|
||||||
widget = QWebEngineView()
|
|
||||||
widget.setZoomFactor(Config.WEB_ZOOM_FACTOR)
|
|
||||||
self.last_update[widget] = dt.datetime.now()
|
|
||||||
_ = self.addTab(widget, "")
|
|
||||||
|
|
||||||
def open_tab(self, url: str, title: str) -> None:
|
|
||||||
"""
|
|
||||||
Open passed URL. If URL currently displayed, switch to that tab.
|
|
||||||
Create new tab if we're below the maximum
|
|
||||||
number otherwise reuse oldest content tab.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if url in self.tabtitles.values():
|
|
||||||
self.setCurrentIndex(
|
|
||||||
list(self.tabtitles.keys())[list(self.tabtitles.values()).index(url)]
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
short_title = title[: Config.INFO_TAB_TITLE_LENGTH]
|
|
||||||
|
|
||||||
if self.count() < Config.MAX_INFO_TABS:
|
|
||||||
# Create a new tab
|
|
||||||
widget = QWebEngineView()
|
|
||||||
widget.setZoomFactor(Config.WEB_ZOOM_FACTOR)
|
|
||||||
tab_index = self.addTab(widget, short_title)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Reuse oldest widget
|
|
||||||
widget = min(self.last_update, key=self.last_update.get) # type: ignore
|
|
||||||
tab_index = self.indexOf(widget)
|
|
||||||
self.setTabText(tab_index, short_title)
|
|
||||||
|
|
||||||
widget.setUrl(QUrl(url))
|
|
||||||
self.last_update[widget] = dt.datetime.now()
|
|
||||||
self.tabtitles[tab_index] = url
|
|
||||||
|
|
||||||
# Show newly updated tab
|
|
||||||
self.setCurrentIndex(tab_index)
|
|
||||||
@ -19,7 +19,7 @@ from sqlalchemy import (
|
|||||||
)
|
)
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from sqlalchemy.orm.exc import NoResultFound
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload, selectinload
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
@ -36,7 +36,6 @@ if DATABASE_URL is None:
|
|||||||
if "unittest" in sys.modules and "sqlite" not in DATABASE_URL:
|
if "unittest" in sys.modules and "sqlite" not in DATABASE_URL:
|
||||||
raise ValueError("Unit tests running on non-Sqlite database")
|
raise ValueError("Unit tests running on non-Sqlite database")
|
||||||
db = DatabaseManager.get_instance(DATABASE_URL, engine_options=Config.ENGINE_OPTIONS).db
|
db = DatabaseManager.get_instance(DATABASE_URL, engine_options=Config.ENGINE_OPTIONS).db
|
||||||
db.create_all()
|
|
||||||
|
|
||||||
|
|
||||||
# Database classes
|
# Database classes
|
||||||
@ -236,10 +235,23 @@ class Playlists(dbtables.PlaylistsTable):
|
|||||||
|
|
||||||
return session.scalars(
|
return session.scalars(
|
||||||
select(cls)
|
select(cls)
|
||||||
.filter(cls.is_template.is_(False))
|
.filter(
|
||||||
|
cls.is_template.is_(False),
|
||||||
|
~cls.query.has()
|
||||||
|
)
|
||||||
.order_by(cls.last_used.desc())
|
.order_by(cls.last_used.desc())
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_all_queries(cls, session: Session) -> Sequence["Playlists"]:
|
||||||
|
"""Returns a list of all query lists ordered by name"""
|
||||||
|
|
||||||
|
return session.scalars(
|
||||||
|
select(cls)
|
||||||
|
.where(cls.query.has())
|
||||||
|
.order_by(cls.name)
|
||||||
|
).all()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all_templates(cls, session: Session) -> Sequence["Playlists"]:
|
def get_all_templates(cls, session: Session) -> Sequence["Playlists"]:
|
||||||
"""Returns a list of all templates ordered by name"""
|
"""Returns a list of all templates ordered by name"""
|
||||||
@ -257,6 +269,7 @@ class Playlists(dbtables.PlaylistsTable):
|
|||||||
.filter(
|
.filter(
|
||||||
cls.open.is_(False),
|
cls.open.is_(False),
|
||||||
cls.is_template.is_(False),
|
cls.is_template.is_(False),
|
||||||
|
~cls.query.has()
|
||||||
)
|
)
|
||||||
.order_by(cls.last_used.desc())
|
.order_by(cls.last_used.desc())
|
||||||
).all()
|
).all()
|
||||||
@ -268,7 +281,13 @@ class Playlists(dbtables.PlaylistsTable):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
return session.scalars(
|
return session.scalars(
|
||||||
select(cls).where(cls.open.is_(True)).order_by(cls.tab)
|
select(cls)
|
||||||
|
.where(
|
||||||
|
cls.open.is_(True),
|
||||||
|
~cls.query.has()
|
||||||
|
)
|
||||||
|
.order_by(cls.tab)
|
||||||
|
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
def mark_open(self) -> None:
|
def mark_open(self) -> None:
|
||||||
@ -312,6 +331,26 @@ class Playlists(dbtables.PlaylistsTable):
|
|||||||
PlaylistRows.copy_playlist(session, playlist_id, template.id)
|
PlaylistRows.copy_playlist(session, playlist_id, template.id)
|
||||||
|
|
||||||
|
|
||||||
|
class Queries(dbtables.QueriesTable):
|
||||||
|
def __init__(self, session: Session, playlist_id: int, query: str = "") -> None:
|
||||||
|
self.playlist_id = playlist_id
|
||||||
|
self.query = query
|
||||||
|
session.add(self)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_query(session: Session, playlist_id: int) -> str:
|
||||||
|
"""
|
||||||
|
Return query associated with playlist or null string if none
|
||||||
|
"""
|
||||||
|
|
||||||
|
return session.execute(
|
||||||
|
select(Queries.query).where(
|
||||||
|
Queries.playlist_id == playlist_id
|
||||||
|
)
|
||||||
|
).scalar_one()
|
||||||
|
|
||||||
|
|
||||||
class PlaylistRows(dbtables.PlaylistRowsTable):
|
class PlaylistRows(dbtables.PlaylistRowsTable):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Standard library imports
|
# Standard library imports
|
||||||
from slugify import slugify # type: ignore
|
from slugify import slugify # type: ignore
|
||||||
from typing import Optional
|
from typing import Callable, Optional
|
||||||
import argparse
|
import argparse
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import os
|
import os
|
||||||
@ -19,6 +19,7 @@ from PyQt6.QtCore import (
|
|||||||
QTimer,
|
QTimer,
|
||||||
)
|
)
|
||||||
from PyQt6.QtGui import (
|
from PyQt6.QtGui import (
|
||||||
|
QAction,
|
||||||
QCloseEvent,
|
QCloseEvent,
|
||||||
QColor,
|
QColor,
|
||||||
QIcon,
|
QIcon,
|
||||||
@ -62,11 +63,16 @@ from log import log
|
|||||||
from models import db, Playdates, PlaylistRows, Playlists, Settings, Tracks
|
from models import db, Playdates, PlaylistRows, Playlists, Settings, Tracks
|
||||||
from music_manager import RowAndTrack, track_sequence
|
from music_manager import RowAndTrack, track_sequence
|
||||||
from playlistmodel import PlaylistModel, PlaylistProxyModel
|
from playlistmodel import PlaylistModel, PlaylistProxyModel
|
||||||
|
from querylistmodel import QuerylistModel
|
||||||
from playlists import PlaylistTab
|
from playlists import PlaylistTab
|
||||||
|
from querylists import QuerylistTab
|
||||||
from ui import icons_rc # noqa F401
|
from ui import icons_rc # noqa F401
|
||||||
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore
|
from ui.dlg_SelectPlaylist_ui import Ui_dlgSelectPlaylist # type: ignore
|
||||||
from ui.downloadcsv_ui import Ui_DateSelect # type: ignore
|
from ui.downloadcsv_ui import Ui_DateSelect # type: ignore
|
||||||
from ui.main_window_ui import Ui_MainWindow # type: ignore
|
from ui.main_window_header_ui import Ui_HeaderSection # type: ignore
|
||||||
|
from ui.main_window_playlist_ui import Ui_PlaylistSection # type: ignore
|
||||||
|
from ui.main_window_footer_ui import Ui_FooterSection # type: ignore
|
||||||
|
|
||||||
from utilities import check_db, update_bitrates
|
from utilities import check_db, update_bitrates
|
||||||
import helpers
|
import helpers
|
||||||
|
|
||||||
@ -366,12 +372,47 @@ class TemplateSelectorDialog(QDialog):
|
|||||||
self.reject()
|
self.reject()
|
||||||
|
|
||||||
|
|
||||||
class Window(QMainWindow, Ui_MainWindow):
|
# Per-section UI files
|
||||||
|
class HeaderSection(QWidget, Ui_HeaderSection):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
|
||||||
|
class PlaylistSection(QWidget, Ui_PlaylistSection):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
|
||||||
|
class FooterSection(QWidget, Ui_FooterSection):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QMainWindow):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, parent: Optional[QWidget] = None, *args: list, **kwargs: dict
|
self, parent: Optional[QWidget] = None, *args: list, **kwargs: dict
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setupUi(self)
|
|
||||||
|
# Build main window from per-section classes defined above
|
||||||
|
central_widget = QWidget(self)
|
||||||
|
self.setCentralWidget(central_widget)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(central_widget)
|
||||||
|
self.header_section = HeaderSection()
|
||||||
|
self.playlist_section = PlaylistSection()
|
||||||
|
self.footer_section = FooterSection()
|
||||||
|
|
||||||
|
layout.addWidget(self.header_section)
|
||||||
|
layout.addWidget(self.playlist_section)
|
||||||
|
layout.addWidget(self.footer_section)
|
||||||
|
|
||||||
|
self.setWindowTitle(Config.MAIN_WINDOW_TITLE)
|
||||||
|
# Add menu bar
|
||||||
|
self.create_menu_bar()
|
||||||
|
|
||||||
self.timer10: QTimer = QTimer()
|
self.timer10: QTimer = QTimer()
|
||||||
self.timer100: QTimer = QTimer()
|
self.timer100: QTimer = QTimer()
|
||||||
@ -380,17 +421,19 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
self.set_main_window_size()
|
self.set_main_window_size()
|
||||||
self.lblSumPlaytime = QLabel("")
|
self.lblSumPlaytime = QLabel("")
|
||||||
self.statusbar.addPermanentWidget(self.lblSumPlaytime)
|
self.statusbar = self.statusBar()
|
||||||
self.txtSearch = QLineEdit()
|
if self.statusbar:
|
||||||
self.txtSearch.setHidden(True)
|
self.statusbar.addPermanentWidget(self.lblSumPlaytime)
|
||||||
self.statusbar.addWidget(self.txtSearch)
|
self.txtSearch = QLineEdit()
|
||||||
|
self.txtSearch.setHidden(True)
|
||||||
|
self.statusbar.addWidget(self.txtSearch)
|
||||||
self.hide_played_tracks = False
|
self.hide_played_tracks = False
|
||||||
self.preview_manager = PreviewManager()
|
self.preview_manager = PreviewManager()
|
||||||
|
|
||||||
self.widgetFadeVolume.hideAxis("bottom")
|
self.footer_section.widgetFadeVolume.hideAxis("bottom")
|
||||||
self.widgetFadeVolume.hideAxis("left")
|
self.footer_section.widgetFadeVolume.hideAxis("left")
|
||||||
self.widgetFadeVolume.setDefaultPadding(0)
|
self.footer_section.widgetFadeVolume.setDefaultPadding(0)
|
||||||
self.widgetFadeVolume.setBackground(Config.FADE_CURVE_BACKGROUND)
|
self.footer_section.widgetFadeVolume.setBackground(Config.FADE_CURVE_BACKGROUND)
|
||||||
|
|
||||||
self.move_source_rows: Optional[list[int]] = None
|
self.move_source_rows: Optional[list[int]] = None
|
||||||
self.move_source_model: Optional[PlaylistModel] = None
|
self.move_source_model: Optional[PlaylistModel] = None
|
||||||
@ -407,12 +450,11 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.importer: Optional[FileImporter] = None
|
self.importer: Optional[FileImporter] = None
|
||||||
self.current = Current()
|
self.current = Current()
|
||||||
|
|
||||||
if not Config.USE_INTERNAL_BROWSER:
|
webbrowser.register(
|
||||||
webbrowser.register(
|
"browser",
|
||||||
"browser",
|
None,
|
||||||
None,
|
webbrowser.BackgroundBrowser(Config.EXTERNAL_BROWSER_PATH),
|
||||||
webbrowser.BackgroundBrowser(Config.EXTERNAL_BROWSER_PATH),
|
)
|
||||||
)
|
|
||||||
|
|
||||||
# Set up shortcut key for instant logging from keyboard
|
# Set up shortcut key for instant logging from keyboard
|
||||||
self.action_quicklog = QShortcut(QKeySequence("Ctrl+L"), self)
|
self.action_quicklog = QShortcut(QKeySequence("Ctrl+L"), self)
|
||||||
@ -421,6 +463,121 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.load_last_playlists()
|
self.load_last_playlists()
|
||||||
self.stop_autoplay = False
|
self.stop_autoplay = False
|
||||||
|
|
||||||
|
def create_action(
|
||||||
|
self, text: str, handler: Callable, shortcut: Optional[str] = None
|
||||||
|
) -> QAction:
|
||||||
|
"""
|
||||||
|
Helper function to create an action, bind it to a method, and set a shortcut if provided.
|
||||||
|
"""
|
||||||
|
|
||||||
|
action = QAction(text, self)
|
||||||
|
action.triggered.connect(handler)
|
||||||
|
if shortcut:
|
||||||
|
action.setShortcut(shortcut) # Adding the shortcut
|
||||||
|
return action
|
||||||
|
|
||||||
|
def create_menu_bar(self):
|
||||||
|
menu_bar = self.menuBar()
|
||||||
|
|
||||||
|
# File Menu
|
||||||
|
file_menu = menu_bar.addMenu("&File")
|
||||||
|
file_menu.addAction(
|
||||||
|
self.create_action("Open Playlist", self.open_playlist, "Ctrl+O")
|
||||||
|
)
|
||||||
|
file_menu.addAction(self.create_action("New Playlist", self.new_playlist))
|
||||||
|
file_menu.addAction(
|
||||||
|
self.create_action("Close Playlist", self.close_playlist_tab)
|
||||||
|
)
|
||||||
|
file_menu.addAction(self.create_action("Rename Playlist", self.rename_playlist))
|
||||||
|
file_menu.addAction(self.create_action("Delete Playlist", self.delete_playlist))
|
||||||
|
file_menu.addSeparator()
|
||||||
|
file_menu.addAction(
|
||||||
|
self.create_action("Save as Template", self.save_as_template)
|
||||||
|
)
|
||||||
|
file_menu.addAction(
|
||||||
|
self.create_action("Manage Templates", self.manage_templates)
|
||||||
|
)
|
||||||
|
file_menu.addSeparator()
|
||||||
|
file_menu.addAction(
|
||||||
|
self.create_action(
|
||||||
|
"Import Files", self.import_files_wrapper, "Ctrl+Shift+I"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
file_menu.addSeparator()
|
||||||
|
file_menu.addAction(
|
||||||
|
self.create_action("Exit", self.close)
|
||||||
|
) # Default action for closing
|
||||||
|
|
||||||
|
# Playlist Menu
|
||||||
|
playlist_menu = menu_bar.addMenu("&Playlist")
|
||||||
|
playlist_menu.addSeparator()
|
||||||
|
playlist_menu.addAction(
|
||||||
|
self.create_action("Insert Track", self.insert_track, "Ctrl+T")
|
||||||
|
)
|
||||||
|
playlist_menu.addAction(
|
||||||
|
self.create_action("Insert Section Header", self.insert_header, "Ctrl+H")
|
||||||
|
)
|
||||||
|
playlist_menu.addSeparator()
|
||||||
|
playlist_menu.addAction(
|
||||||
|
self.create_action("Mark for Moving", self.mark_rows_for_moving, "Ctrl+C")
|
||||||
|
)
|
||||||
|
playlist_menu.addAction(self.create_action("Paste", self.paste_rows, "Ctrl+V"))
|
||||||
|
playlist_menu.addSeparator()
|
||||||
|
playlist_menu.addAction(
|
||||||
|
self.create_action("Export Playlist", self.export_playlist_tab)
|
||||||
|
)
|
||||||
|
playlist_menu.addAction(
|
||||||
|
self.create_action(
|
||||||
|
"Download CSV of Played Tracks", self.download_played_tracks
|
||||||
|
)
|
||||||
|
)
|
||||||
|
playlist_menu.addSeparator()
|
||||||
|
playlist_menu.addAction(
|
||||||
|
self.create_action(
|
||||||
|
"Select Duplicate Rows",
|
||||||
|
lambda: self.active_tab().select_duplicate_rows(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
playlist_menu.addAction(self.create_action("Move Selected", self.move_selected))
|
||||||
|
playlist_menu.addAction(self.create_action("Move Unplayed", self.move_unplayed))
|
||||||
|
|
||||||
|
# Clear Selection with Escape key. Save in module so we can
|
||||||
|
# enable/disable it later
|
||||||
|
self.action_Clear_selection = self.create_action(
|
||||||
|
"Clear Selection", self.clear_selection, "Esc"
|
||||||
|
)
|
||||||
|
playlist_menu.addAction(self.action_Clear_selection)
|
||||||
|
|
||||||
|
# Music Menu
|
||||||
|
music_menu = menu_bar.addMenu("&Music")
|
||||||
|
music_menu.addAction(
|
||||||
|
self.create_action("Set Next", self.set_selected_track_next, "Ctrl+N")
|
||||||
|
)
|
||||||
|
music_menu.addAction(self.create_action("Play Next", self.play_next, "Return"))
|
||||||
|
music_menu.addAction(self.create_action("Fade", self.fade, "Ctrl+Z"))
|
||||||
|
music_menu.addAction(self.create_action("Stop", self.stop, "Ctrl+Alt+S"))
|
||||||
|
music_menu.addAction(self.create_action("Resume", self.resume, "Ctrl+R"))
|
||||||
|
music_menu.addAction(
|
||||||
|
self.create_action("Skip to Next", self.play_next, "Ctrl+Alt+Return")
|
||||||
|
)
|
||||||
|
music_menu.addSeparator()
|
||||||
|
music_menu.addAction(self.create_action("Search", self.search_playlist, "/"))
|
||||||
|
music_menu.addAction(
|
||||||
|
self.create_action(
|
||||||
|
"Search Title in Wikipedia", self.lookup_row_in_wikipedia, "Ctrl+W"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
music_menu.addAction(
|
||||||
|
self.create_action(
|
||||||
|
"Search Title in Songfacts", self.lookup_row_in_songfacts, "Ctrl+S"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Help Menu
|
||||||
|
help_menu = menu_bar.addMenu("Help")
|
||||||
|
help_menu.addAction(self.create_action("About", self.about))
|
||||||
|
help_menu.addAction(self.create_action("Debug", self.debug))
|
||||||
|
|
||||||
def about(self) -> None:
|
def about(self) -> None:
|
||||||
"""Get git tag and database name"""
|
"""Get git tag and database name"""
|
||||||
|
|
||||||
@ -446,7 +603,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
return self.current.base_model
|
return self.current.base_model
|
||||||
|
|
||||||
def active_tab(self) -> PlaylistTab:
|
def active_tab(self) -> PlaylistTab:
|
||||||
return self.tabPlaylist.currentWidget()
|
return self.playlist_section.tabPlaylist.currentWidget()
|
||||||
|
|
||||||
def clear_next(self) -> None:
|
def clear_next(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -482,8 +639,10 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
with db.Session() as session:
|
with db.Session() as session:
|
||||||
# Save tab number of open playlists
|
# Save tab number of open playlists
|
||||||
open_playlist_ids: dict[int, int] = {}
|
open_playlist_ids: dict[int, int] = {}
|
||||||
for idx in range(self.tabPlaylist.count()):
|
for idx in range(self.playlist_section.tabPlaylist.count()):
|
||||||
open_playlist_ids[self.tabPlaylist.widget(idx).playlist_id] = idx
|
open_playlist_ids[
|
||||||
|
self.playlist_section.tabPlaylist.widget(idx).playlist_id
|
||||||
|
] = idx
|
||||||
Playlists.clear_tabs(session, list(open_playlist_ids.keys()))
|
Playlists.clear_tabs(session, list(open_playlist_ids.keys()))
|
||||||
for playlist_id, idx in open_playlist_ids.items():
|
for playlist_id, idx in open_playlist_ids.items():
|
||||||
playlist = session.get(Playlists, playlist_id)
|
playlist = session.get(Playlists, playlist_id)
|
||||||
@ -492,15 +651,12 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
playlist.tab = idx
|
playlist.tab = idx
|
||||||
|
|
||||||
# Save window attributes
|
# Save window attributes
|
||||||
splitter_top, splitter_bottom = self.splitter.sizes()
|
|
||||||
attributes_to_save = dict(
|
attributes_to_save = dict(
|
||||||
mainwindow_height=self.height(),
|
mainwindow_height=self.height(),
|
||||||
mainwindow_width=self.width(),
|
mainwindow_width=self.width(),
|
||||||
mainwindow_x=self.x(),
|
mainwindow_x=self.x(),
|
||||||
mainwindow_y=self.y(),
|
mainwindow_y=self.y(),
|
||||||
splitter_top=splitter_top,
|
active_tab=self.playlist_section.tabPlaylist.currentIndex(),
|
||||||
splitter_bottom=splitter_bottom,
|
|
||||||
active_tab=self.tabPlaylist.currentIndex(),
|
|
||||||
)
|
)
|
||||||
for name, value in attributes_to_save.items():
|
for name, value in attributes_to_save.items():
|
||||||
record = Settings.get_setting(session, name)
|
record = Settings.get_setting(session, name)
|
||||||
@ -515,7 +671,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
Close active playlist tab, called by menu item
|
Close active playlist tab, called by menu item
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return self.close_tab(self.tabPlaylist.currentIndex())
|
return self.close_tab(self.playlist_section.tabPlaylist.currentIndex())
|
||||||
|
|
||||||
def close_tab(self, tab_index: int) -> bool:
|
def close_tab(self, tab_index: int) -> bool:
|
||||||
"""
|
"""
|
||||||
@ -525,7 +681,9 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
Return True if tab closed else False.
|
Return True if tab closed else False.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
closing_tab_playlist_id = self.tabPlaylist.widget(tab_index).playlist_id
|
closing_tab_playlist_id = self.playlist_section.tabPlaylist.widget(
|
||||||
|
tab_index
|
||||||
|
).playlist_id
|
||||||
|
|
||||||
# Don't close current track playlist
|
# Don't close current track playlist
|
||||||
if track_sequence.current is not None:
|
if track_sequence.current is not None:
|
||||||
@ -554,66 +712,30 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
playlist.close(session)
|
playlist.close(session)
|
||||||
|
|
||||||
# Close playlist and remove tab
|
# Close playlist and remove tab
|
||||||
self.tabPlaylist.widget(tab_index).close()
|
self.playlist_section.tabPlaylist.widget(tab_index).close()
|
||||||
self.tabPlaylist.removeTab(tab_index)
|
self.playlist_section.tabPlaylist.removeTab(tab_index)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def connect_signals_slots(self) -> None:
|
def connect_signals_slots(self) -> None:
|
||||||
self.action_About.triggered.connect(self.about)
|
# Menu bars connections are in create_menu_bar()
|
||||||
self.action_Clear_selection.triggered.connect(self.clear_selection)
|
|
||||||
self.actionClosePlaylist.triggered.connect(self.close_playlist_tab)
|
|
||||||
self.actionDebug.triggered.connect(self.debug)
|
|
||||||
self.actionDeletePlaylist.triggered.connect(self.delete_playlist)
|
|
||||||
self.actionDownload_CSV_of_played_tracks.triggered.connect(
|
|
||||||
self.download_played_tracks
|
|
||||||
)
|
|
||||||
self.actionExport_playlist.triggered.connect(self.export_playlist_tab)
|
|
||||||
self.actionFade.triggered.connect(self.fade)
|
|
||||||
self.actionImport_files.triggered.connect(self.import_files_wrapper)
|
|
||||||
self.actionInsertSectionHeader.triggered.connect(self.insert_header)
|
|
||||||
self.actionInsertTrack.triggered.connect(self.insert_track)
|
|
||||||
self.actionManage_templates.triggered.connect(self.manage_templates)
|
|
||||||
self.actionMark_for_moving.triggered.connect(self.mark_rows_for_moving)
|
|
||||||
self.actionMoveSelected.triggered.connect(self.move_selected)
|
|
||||||
self.actionMoveUnplayed.triggered.connect(self.move_unplayed)
|
|
||||||
self.actionNewPlaylist.triggered.connect(self.new_playlist)
|
|
||||||
self.actionOpenPlaylist.triggered.connect(self.open_playlist)
|
|
||||||
self.actionPaste.triggered.connect(self.paste_rows)
|
|
||||||
self.actionPlay_next.triggered.connect(self.play_next)
|
|
||||||
self.actionRenamePlaylist.triggered.connect(self.rename_playlist)
|
|
||||||
self.actionResume.triggered.connect(self.resume)
|
|
||||||
self.actionSave_as_template.triggered.connect(self.save_as_template)
|
|
||||||
self.actionSearch_title_in_Songfacts.triggered.connect(
|
|
||||||
self.lookup_row_in_songfacts
|
|
||||||
)
|
|
||||||
self.actionSearch_title_in_Wikipedia.triggered.connect(
|
|
||||||
self.lookup_row_in_wikipedia
|
|
||||||
)
|
|
||||||
self.actionSearch.triggered.connect(self.search_playlist)
|
|
||||||
self.actionSelect_duplicate_rows.triggered.connect(
|
|
||||||
lambda: self.active_tab().select_duplicate_rows()
|
|
||||||
)
|
|
||||||
self.actionSetNext.triggered.connect(self.set_selected_track_next)
|
|
||||||
self.actionSkipToNext.triggered.connect(self.play_next)
|
|
||||||
self.actionStop.triggered.connect(self.stop)
|
|
||||||
|
|
||||||
self.btnDrop3db.clicked.connect(self.drop3db)
|
self.footer_section.btnDrop3db.clicked.connect(self.drop3db)
|
||||||
self.btnFade.clicked.connect(self.fade)
|
self.footer_section.btnFade.clicked.connect(self.fade)
|
||||||
self.btnHidePlayed.clicked.connect(self.hide_played)
|
self.footer_section.btnHidePlayed.clicked.connect(self.hide_played)
|
||||||
self.btnPreviewArm.clicked.connect(self.preview_arm)
|
self.footer_section.btnPreviewArm.clicked.connect(self.preview_arm)
|
||||||
self.btnPreviewBack.clicked.connect(self.preview_back)
|
self.footer_section.btnPreviewBack.clicked.connect(self.preview_back)
|
||||||
self.btnPreview.clicked.connect(self.preview)
|
self.footer_section.btnPreview.clicked.connect(self.preview)
|
||||||
self.btnPreviewEnd.clicked.connect(self.preview_end)
|
self.footer_section.btnPreviewEnd.clicked.connect(self.preview_end)
|
||||||
self.btnPreviewFwd.clicked.connect(self.preview_fwd)
|
self.footer_section.btnPreviewFwd.clicked.connect(self.preview_fwd)
|
||||||
self.btnPreviewMark.clicked.connect(self.preview_mark)
|
self.footer_section.btnPreviewMark.clicked.connect(self.preview_mark)
|
||||||
self.btnPreviewStart.clicked.connect(self.preview_start)
|
self.footer_section.btnPreviewStart.clicked.connect(self.preview_start)
|
||||||
self.btnStop.clicked.connect(self.stop)
|
self.footer_section.btnStop.clicked.connect(self.stop)
|
||||||
self.hdrCurrentTrack.clicked.connect(self.show_current)
|
self.header_section.hdrCurrentTrack.clicked.connect(self.show_current)
|
||||||
self.hdrNextTrack.clicked.connect(self.show_next)
|
self.header_section.hdrNextTrack.clicked.connect(self.show_next)
|
||||||
self.tabPlaylist.currentChanged.connect(self.tab_change)
|
self.playlist_section.tabPlaylist.currentChanged.connect(self.tab_change)
|
||||||
self.tabPlaylist.tabCloseRequested.connect(self.close_tab)
|
self.playlist_section.tabPlaylist.tabCloseRequested.connect(self.close_tab)
|
||||||
self.tabBar = self.tabPlaylist.tabBar()
|
self.tabBar = self.playlist_section.tabPlaylist.tabBar()
|
||||||
self.txtSearch.textChanged.connect(self.search_playlist_text_changed)
|
self.txtSearch.textChanged.connect(self.search_playlist_text_changed)
|
||||||
|
|
||||||
self.signals.enable_escape_signal.connect(self.enable_escape)
|
self.signals.enable_escape_signal.connect(self.enable_escape)
|
||||||
@ -648,7 +770,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
def create_playlist_tab(self, playlist: Playlists) -> int:
|
def create_playlist_tab(self, playlist: Playlists) -> int:
|
||||||
"""
|
"""
|
||||||
Take the passed proxy model, create a playlist tab and
|
Take the passed playlist, create a playlist tab and
|
||||||
add tab to display. Return index number of tab.
|
add tab to display. Return index number of tab.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -661,12 +783,31 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
# Create tab
|
# Create tab
|
||||||
playlist_tab = PlaylistTab(musicmuster=self, model=proxy_model)
|
playlist_tab = PlaylistTab(musicmuster=self, model=proxy_model)
|
||||||
idx = self.tabPlaylist.addTab(playlist_tab, playlist.name)
|
idx = self.playlist_section.tabPlaylist.addTab(playlist_tab, playlist.name)
|
||||||
|
|
||||||
log.debug(f"create_playlist_tab() returned: {idx=}")
|
log.debug(f"create_playlist_tab() returned: {idx=}")
|
||||||
|
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
|
def create_querylist_tab(self, querylist: Playlists) -> int:
|
||||||
|
"""
|
||||||
|
Take the passed querylist, create a querylist tab and
|
||||||
|
add tab to display. Return index number of tab.
|
||||||
|
"""
|
||||||
|
|
||||||
|
log.debug(f"create_querylist_tab({querylist=})")
|
||||||
|
|
||||||
|
# Create model and proxy model
|
||||||
|
base_model = QuerylistModel(querylist.id)
|
||||||
|
|
||||||
|
# Create tab
|
||||||
|
querylist_tab = QuerylistTab(musicmuster=self, model=base_model)
|
||||||
|
idx = self.playlist_section.tabPlaylist.addTab(querylist_tab, querylist.name)
|
||||||
|
|
||||||
|
log.debug(f"create_querylist_tab() returned: {idx=}")
|
||||||
|
|
||||||
|
return idx
|
||||||
|
|
||||||
def current_row_or_end(self) -> int:
|
def current_row_or_end(self) -> int:
|
||||||
"""
|
"""
|
||||||
If a row or rows are selected, return the row number of the first
|
If a row or rows are selected, return the row number of the first
|
||||||
@ -733,7 +874,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
"""Drop music level by 3db if button checked"""
|
"""Drop music level by 3db if button checked"""
|
||||||
|
|
||||||
if track_sequence.current:
|
if track_sequence.current:
|
||||||
track_sequence.current.drop3db(self.btnDrop3db.isChecked())
|
track_sequence.current.drop3db(self.footer_section.btnDrop3db.isChecked())
|
||||||
|
|
||||||
def enable_escape(self, enabled: bool) -> None:
|
def enable_escape(self, enabled: bool) -> None:
|
||||||
"""
|
"""
|
||||||
@ -770,10 +911,10 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.current.base_model.previous_track_ended()
|
self.current.base_model.previous_track_ended()
|
||||||
|
|
||||||
# Reset clocks
|
# Reset clocks
|
||||||
self.frame_fade.setStyleSheet("")
|
self.footer_section.frame_fade.setStyleSheet("")
|
||||||
self.frame_silent.setStyleSheet("")
|
self.footer_section.frame_silent.setStyleSheet("")
|
||||||
self.label_fade_timer.setText("00:00")
|
self.footer_section.label_fade_timer.setText("00:00")
|
||||||
self.label_silent_timer.setText("00:00")
|
self.footer_section.label_silent_timer.setText("00:00")
|
||||||
|
|
||||||
# Update headers
|
# Update headers
|
||||||
self.update_headers()
|
self.update_headers()
|
||||||
@ -903,7 +1044,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# Set active tab
|
# Set active tab
|
||||||
record = Settings.get_setting(session, "active_tab")
|
record = Settings.get_setting(session, "active_tab")
|
||||||
if record.f_int is not None and record.f_int >= 0:
|
if record.f_int is not None and record.f_int >= 0:
|
||||||
self.tabPlaylist.setCurrentIndex(record.f_int)
|
self.playlist_section.tabPlaylist.setCurrentIndex(record.f_int)
|
||||||
|
|
||||||
# Tabs may move during use. Rather than track where tabs
|
# Tabs may move during use. Rather than track where tabs
|
||||||
# are, we record the tab index when we close the main
|
# are, we record the tab index when we close the main
|
||||||
@ -961,7 +1102,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# Simply load the template as a playlist. Any changes
|
# Simply load the template as a playlist. Any changes
|
||||||
# made will persist
|
# made will persist
|
||||||
idx = self.create_playlist_tab(playlist)
|
idx = self.create_playlist_tab(playlist)
|
||||||
self.tabPlaylist.setCurrentIndex(idx)
|
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
|
||||||
|
|
||||||
elif action == "Delete":
|
elif action == "Delete":
|
||||||
if helpers.ask_yes_no(
|
if helpers.ask_yes_no(
|
||||||
@ -1097,7 +1238,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# the database before it is opened by the model.
|
# the database before it is opened by the model.
|
||||||
session.commit()
|
session.commit()
|
||||||
idx = self.create_playlist_tab(playlist)
|
idx = self.create_playlist_tab(playlist)
|
||||||
self.tabPlaylist.setCurrentIndex(idx)
|
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
|
||||||
else:
|
else:
|
||||||
log.error("Playlist failed to create")
|
log.error("Playlist failed to create")
|
||||||
|
|
||||||
@ -1114,7 +1255,20 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
playlist.mark_open()
|
playlist.mark_open()
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
self.tabPlaylist.setCurrentIndex(idx)
|
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
|
||||||
|
|
||||||
|
def open_querylist(self) -> None:
|
||||||
|
"""Open existing querylist"""
|
||||||
|
|
||||||
|
with db.Session() as session:
|
||||||
|
querylists = Playlists.get_all_queries(session)
|
||||||
|
dlg = SelectPlaylistDialog(self, playlists=querylists, session=session)
|
||||||
|
dlg.exec()
|
||||||
|
querylist = dlg.playlist
|
||||||
|
if querylist:
|
||||||
|
idx = self.create_querylist_tab(querylist)
|
||||||
|
|
||||||
|
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
|
||||||
|
|
||||||
def open_songfacts_browser(self, title: str) -> None:
|
def open_songfacts_browser(self, title: str) -> None:
|
||||||
"""Search Songfacts for title"""
|
"""Search Songfacts for title"""
|
||||||
@ -1123,10 +1277,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
log.info(f"Songfacts browser tab for {title=}")
|
log.info(f"Songfacts browser tab for {title=}")
|
||||||
url = f"https://www.songfacts.com/search/songs/{slug}"
|
url = f"https://www.songfacts.com/search/songs/{slug}"
|
||||||
|
|
||||||
if Config.USE_INTERNAL_BROWSER:
|
webbrowser.get("browser").open_new_tab(url)
|
||||||
self.tabInfolist.open_tab(url, title)
|
|
||||||
else:
|
|
||||||
webbrowser.get("browser").open_new_tab(url)
|
|
||||||
|
|
||||||
def open_wikipedia_browser(self, title: str) -> None:
|
def open_wikipedia_browser(self, title: str) -> None:
|
||||||
"""Search Wikipedia for title"""
|
"""Search Wikipedia for title"""
|
||||||
@ -1135,10 +1286,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
log.info(f"Wikipedia browser tab for {title=}")
|
log.info(f"Wikipedia browser tab for {title=}")
|
||||||
url = f"https://www.wikipedia.org/w/index.php?search={str}"
|
url = f"https://www.wikipedia.org/w/index.php?search={str}"
|
||||||
|
|
||||||
if Config.USE_INTERNAL_BROWSER:
|
webbrowser.get("browser").open_new_tab(url)
|
||||||
self.tabInfolist.open_tab(url, title)
|
|
||||||
else:
|
|
||||||
webbrowser.get("browser").open_new_tab(url)
|
|
||||||
|
|
||||||
def paste_rows(self) -> None:
|
def paste_rows(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1222,8 +1370,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
self.clear_next()
|
self.clear_next()
|
||||||
|
|
||||||
# Restore volume if -3dB active
|
# Restore volume if -3dB active
|
||||||
if self.btnDrop3db.isChecked():
|
if self.footer_section.btnDrop3db.isChecked():
|
||||||
self.btnDrop3db.setChecked(False)
|
self.footer_section.btnDrop3db.setChecked(False)
|
||||||
|
|
||||||
# Play (new) current track
|
# Play (new) current track
|
||||||
log.debug(f"Play: {track_sequence.current.title}")
|
log.debug(f"Play: {track_sequence.current.title}")
|
||||||
@ -1234,7 +1382,9 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
# Show closing volume graph
|
# Show closing volume graph
|
||||||
if track_sequence.current.fade_graph:
|
if track_sequence.current.fade_graph:
|
||||||
track_sequence.current.fade_graph.GraphWidget = self.widgetFadeVolume
|
track_sequence.current.fade_graph.GraphWidget = (
|
||||||
|
self.footer_section.widgetFadeVolume
|
||||||
|
)
|
||||||
track_sequence.current.fade_graph.clear()
|
track_sequence.current.fade_graph.clear()
|
||||||
track_sequence.current.fade_graph.plot()
|
track_sequence.current.fade_graph.plot()
|
||||||
|
|
||||||
@ -1255,7 +1405,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
tracklist.append(f"{track.title} ({track.artist})")
|
tracklist.append(f"{track.title} ({track.artist})")
|
||||||
tt = "<br>".join(tracklist)
|
tt = "<br>".join(tracklist)
|
||||||
|
|
||||||
self.hdrPreviousTrack.setToolTip(tt)
|
self.header_section.hdrPreviousTrack.setToolTip(tt)
|
||||||
|
|
||||||
def preview(self) -> None:
|
def preview(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1264,7 +1414,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
differently (eg, to headphones).
|
differently (eg, to headphones).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.btnPreview.isChecked():
|
if self.footer_section.btnPreview.isChecked():
|
||||||
# Get track path for first selected track if there is one
|
# Get track path for first selected track if there is one
|
||||||
track_info = self.active_tab().get_selected_row_track_info()
|
track_info = self.active_tab().get_selected_row_track_info()
|
||||||
if not track_info:
|
if not track_info:
|
||||||
@ -1286,7 +1436,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
def preview_arm(self):
|
def preview_arm(self):
|
||||||
"""Manager arm button for setting intro length"""
|
"""Manager arm button for setting intro length"""
|
||||||
|
|
||||||
self.btnPreviewMark.setEnabled(self.btnPreviewArm.isChecked())
|
self.footer_section.btnPreviewMark.setEnabled(self.btnPreviewArm.isChecked())
|
||||||
|
|
||||||
def preview_back(self) -> None:
|
def preview_back(self) -> None:
|
||||||
"""Wind back preview file"""
|
"""Wind back preview file"""
|
||||||
@ -1527,17 +1677,6 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
height = Settings.get_setting(session, "mainwindow_height").f_int or 100
|
height = Settings.get_setting(session, "mainwindow_height").f_int or 100
|
||||||
self.setGeometry(x, y, width, height)
|
self.setGeometry(x, y, width, height)
|
||||||
|
|
||||||
if Config.USE_INTERNAL_BROWSER:
|
|
||||||
splitter_top = (
|
|
||||||
Settings.get_setting(session, "splitter_top").f_int or 100
|
|
||||||
)
|
|
||||||
splitter_bottom = (
|
|
||||||
Settings.get_setting(session, "splitter_bottom").f_int or 100
|
|
||||||
)
|
|
||||||
self.splitter.setSizes([splitter_top, splitter_bottom])
|
|
||||||
else:
|
|
||||||
self.tabInfolist.hide()
|
|
||||||
|
|
||||||
def set_selected_track_next(self) -> None:
|
def set_selected_track_next(self) -> None:
|
||||||
"""
|
"""
|
||||||
Set currently-selected row on visible playlist tab as next track
|
Set currently-selected row on visible playlist tab as next track
|
||||||
@ -1554,8 +1693,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
Find the tab containing the widget and set the text colour
|
Find the tab containing the widget and set the text colour
|
||||||
"""
|
"""
|
||||||
|
|
||||||
idx = self.tabPlaylist.indexOf(widget)
|
idx = self.playlist_section.tabPlaylist.indexOf(widget)
|
||||||
self.tabPlaylist.tabBar().setTabTextColor(idx, colour)
|
self.playlist_section.tabPlaylist.tabBar().setTabTextColor(idx, colour)
|
||||||
|
|
||||||
def show_current(self) -> None:
|
def show_current(self) -> None:
|
||||||
"""Scroll to show current track"""
|
"""Scroll to show current track"""
|
||||||
@ -1582,7 +1721,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
Show status message in status bar for timing milliseconds
|
Show status message in status bar for timing milliseconds
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.statusbar.showMessage(message, timing)
|
if self.statusbar:
|
||||||
|
self.statusbar.showMessage(message, timing)
|
||||||
|
|
||||||
def show_track(self, playlist_track: RowAndTrack) -> None:
|
def show_track(self, playlist_track: RowAndTrack) -> None:
|
||||||
"""Scroll to show track in plt"""
|
"""Scroll to show track in plt"""
|
||||||
@ -1595,9 +1735,12 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
# Switch to correct tab
|
# Switch to correct tab
|
||||||
if playlist_id != self.current.playlist_id:
|
if playlist_id != self.current.playlist_id:
|
||||||
for idx in range(self.tabPlaylist.count()):
|
for idx in range(self.playlist_section.tabPlaylist.count()):
|
||||||
if self.tabPlaylist.widget(idx).playlist_id == playlist_id:
|
if (
|
||||||
self.tabPlaylist.setCurrentIndex(idx)
|
self.playlist_section.tabPlaylist.widget(idx).playlist_id
|
||||||
|
== playlist_id
|
||||||
|
):
|
||||||
|
self.playlist_section.tabPlaylist.setCurrentIndex(idx)
|
||||||
break
|
break
|
||||||
|
|
||||||
self.active_tab().scroll_to_top(playlist_track.row_number)
|
self.active_tab().scroll_to_top(playlist_track.row_number)
|
||||||
@ -1663,34 +1806,38 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# preview.
|
# preview.
|
||||||
intro_ms_remaining = track_sequence.current.time_remaining_intro()
|
intro_ms_remaining = track_sequence.current.time_remaining_intro()
|
||||||
if intro_ms_remaining > 0:
|
if intro_ms_remaining > 0:
|
||||||
self.label_intro_timer.setText(f"{intro_ms_remaining / 1000:.1f}")
|
self.footer_section.label_intro_timer.setText(
|
||||||
|
f"{intro_ms_remaining / 1000:.1f}"
|
||||||
|
)
|
||||||
if intro_ms_remaining <= Config.INTRO_SECONDS_WARNING_MS:
|
if intro_ms_remaining <= Config.INTRO_SECONDS_WARNING_MS:
|
||||||
self.label_intro_timer.setStyleSheet(
|
self.footer_section.label_intro_timer.setStyleSheet(
|
||||||
f"background: {Config.COLOUR_WARNING_TIMER}"
|
f"background: {Config.COLOUR_WARNING_TIMER}"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
if self.label_intro_timer.styleSheet() != "":
|
if self.footer_section.label_intro_timer.styleSheet() != "":
|
||||||
self.label_intro_timer.setStyleSheet("")
|
self.footer_section.label_intro_timer.setStyleSheet("")
|
||||||
self.label_intro_timer.setText("0.0")
|
self.footer_section.label_intro_timer.setText("0.0")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# current track ended during servicing tick
|
# current track ended during servicing tick
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Ensure preview button is reset if preview finishes playing
|
# Ensure preview button is reset if preview finishes playing
|
||||||
# Update preview timer
|
# Update preview timer
|
||||||
if self.btnPreview.isChecked():
|
if self.footer_section.btnPreview.isChecked():
|
||||||
if self.preview_manager.is_playing():
|
if self.preview_manager.is_playing():
|
||||||
self.btnPreview.setChecked(True)
|
self.footer_section.btnPreview.setChecked(True)
|
||||||
minutes, seconds = divmod(
|
minutes, seconds = divmod(
|
||||||
self.preview_manager.get_playtime() / 1000, 60
|
self.preview_manager.get_playtime() / 1000, 60
|
||||||
)
|
)
|
||||||
self.label_intro_timer.setText(f"{int(minutes)}:{seconds:04.1f}")
|
self.footer_section.label_intro_timer.setText(
|
||||||
|
f"{int(minutes)}:{seconds:04.1f}"
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.btnPreview.setChecked(False)
|
self.footer_section.btnPreview.setChecked(False)
|
||||||
self.label_intro_timer.setText("0.0")
|
self.footer_section.label_intro_timer.setText("0.0")
|
||||||
self.label_intro_timer.setStyleSheet("")
|
self.footer_section.label_intro_timer.setStyleSheet("")
|
||||||
self.btnPreview.setChecked(False)
|
self.footer_section.btnPreview.setChecked(False)
|
||||||
|
|
||||||
def tick_1000ms(self) -> None:
|
def tick_1000ms(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1707,7 +1854,9 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
Called every 500ms
|
Called every 500ms
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.lblTOD.setText(dt.datetime.now().strftime(Config.TOD_TIME_FORMAT))
|
self.header_section.lblTOD.setText(
|
||||||
|
dt.datetime.now().strftime(Config.TOD_TIME_FORMAT)
|
||||||
|
)
|
||||||
|
|
||||||
def update_clocks(self) -> None:
|
def update_clocks(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1717,7 +1866,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# If track is playing, update track clocks time and colours
|
# If track is playing, update track clocks time and colours
|
||||||
if track_sequence.current and track_sequence.current.is_playing():
|
if track_sequence.current and track_sequence.current.is_playing():
|
||||||
# Elapsed time
|
# Elapsed time
|
||||||
self.label_elapsed_timer.setText(
|
self.header_section.label_elapsed_timer.setText(
|
||||||
helpers.ms_to_mmss(track_sequence.current.time_playing())
|
helpers.ms_to_mmss(track_sequence.current.time_playing())
|
||||||
+ " / "
|
+ " / "
|
||||||
+ helpers.ms_to_mmss(track_sequence.current.duration)
|
+ helpers.ms_to_mmss(track_sequence.current.duration)
|
||||||
@ -1726,22 +1875,24 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# Time to fade
|
# Time to fade
|
||||||
time_to_fade = track_sequence.current.time_to_fade()
|
time_to_fade = track_sequence.current.time_to_fade()
|
||||||
time_to_silence = track_sequence.current.time_to_silence()
|
time_to_silence = track_sequence.current.time_to_silence()
|
||||||
self.label_fade_timer.setText(helpers.ms_to_mmss(time_to_fade))
|
self.footer_section.label_fade_timer.setText(
|
||||||
|
helpers.ms_to_mmss(time_to_fade)
|
||||||
|
)
|
||||||
|
|
||||||
# If silent in the next 5 seconds, put warning colour on
|
# If silent in the next 5 seconds, put warning colour on
|
||||||
# time to silence box and enable play controls
|
# time to silence box and enable play controls
|
||||||
if time_to_silence <= Config.WARNING_MS_BEFORE_SILENCE:
|
if time_to_silence <= Config.WARNING_MS_BEFORE_SILENCE:
|
||||||
css_silence = f"background: {Config.COLOUR_ENDING_TIMER}"
|
css_silence = f"background: {Config.COLOUR_ENDING_TIMER}"
|
||||||
if self.frame_silent.styleSheet() != css_silence:
|
if self.footer_section.frame_silent.styleSheet() != css_silence:
|
||||||
self.frame_silent.setStyleSheet(css_silence)
|
self.footer_section.frame_silent.setStyleSheet(css_silence)
|
||||||
self.catch_return_key = False
|
self.catch_return_key = False
|
||||||
self.show_status_message("Play controls: Enabled", 0)
|
self.show_status_message("Play controls: Enabled", 0)
|
||||||
|
|
||||||
# Set warning colour on time to silence box when fade starts
|
# Set warning colour on time to silence box when fade starts
|
||||||
elif time_to_fade <= 500:
|
elif time_to_fade <= 500:
|
||||||
css_fade = f"background: {Config.COLOUR_WARNING_TIMER}"
|
css_fade = f"background: {Config.COLOUR_WARNING_TIMER}"
|
||||||
if self.frame_silent.styleSheet() != css_fade:
|
if self.footer_section.frame_silent.styleSheet() != css_fade:
|
||||||
self.frame_silent.setStyleSheet(css_fade)
|
self.footer_section.frame_silent.setStyleSheet(css_fade)
|
||||||
|
|
||||||
# WARNING_MS_BEFORE_FADE milliseconds before fade starts, set
|
# WARNING_MS_BEFORE_FADE milliseconds before fade starts, set
|
||||||
# warning colour on time to silence box and enable play
|
# warning colour on time to silence box and enable play
|
||||||
@ -1749,7 +1900,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
# timer (see play_next() and issue #223).
|
# timer (see play_next() and issue #223).
|
||||||
|
|
||||||
elif time_to_fade <= Config.WARNING_MS_BEFORE_FADE:
|
elif time_to_fade <= Config.WARNING_MS_BEFORE_FADE:
|
||||||
self.frame_fade.setStyleSheet(
|
self.footer_section.frame_fade.setStyleSheet(
|
||||||
f"background: {Config.COLOUR_WARNING_TIMER}"
|
f"background: {Config.COLOUR_WARNING_TIMER}"
|
||||||
)
|
)
|
||||||
self.catch_return_key = False
|
self.catch_return_key = False
|
||||||
@ -1760,10 +1911,12 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
log.debug("issue223: update_clocks: 10ms timer enabled")
|
log.debug("issue223: update_clocks: 10ms timer enabled")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.frame_silent.setStyleSheet("")
|
self.footer_section.frame_silent.setStyleSheet("")
|
||||||
self.frame_fade.setStyleSheet("")
|
self.footer_section.frame_fade.setStyleSheet("")
|
||||||
|
|
||||||
self.label_silent_timer.setText(helpers.ms_to_mmss(time_to_silence))
|
self.footer_section.label_silent_timer.setText(
|
||||||
|
helpers.ms_to_mmss(time_to_silence)
|
||||||
|
)
|
||||||
|
|
||||||
def update_headers(self) -> None:
|
def update_headers(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1771,27 +1924,27 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if track_sequence.previous:
|
if track_sequence.previous:
|
||||||
self.hdrPreviousTrack.setText(
|
self.header_section.hdrPreviousTrack.setText(
|
||||||
f"{track_sequence.previous.title} - {track_sequence.previous.artist}"
|
f"{track_sequence.previous.title} - {track_sequence.previous.artist}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.hdrPreviousTrack.setText("")
|
self.header_section.hdrPreviousTrack.setText("")
|
||||||
|
|
||||||
if track_sequence.current:
|
if track_sequence.current:
|
||||||
self.hdrCurrentTrack.setText(
|
self.header_section.hdrCurrentTrack.setText(
|
||||||
f"{track_sequence.current.title.replace('&', '&&')} - "
|
f"{track_sequence.current.title.replace('&', '&&')} - "
|
||||||
f"{track_sequence.current.artist.replace('&', '&&')}"
|
f"{track_sequence.current.artist.replace('&', '&&')}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.hdrCurrentTrack.setText("")
|
self.header_section.hdrCurrentTrack.setText("")
|
||||||
|
|
||||||
if track_sequence.next:
|
if track_sequence.next:
|
||||||
self.hdrNextTrack.setText(
|
self.header_section.hdrNextTrack.setText(
|
||||||
f"{track_sequence.next.title.replace('&', '&&')} - "
|
f"{track_sequence.next.title.replace('&', '&&')} - "
|
||||||
f"{track_sequence.next.artist.replace('&', '&&')}"
|
f"{track_sequence.next.artist.replace('&', '&&')}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.hdrNextTrack.setText("")
|
self.header_section.hdrNextTrack.setText("")
|
||||||
|
|
||||||
self.update_playlist_icons()
|
self.update_playlist_icons()
|
||||||
|
|
||||||
@ -1810,20 +1963,24 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
set_next = False
|
set_next = False
|
||||||
|
|
||||||
for idx in range(self.tabBar.count()):
|
for idx in range(self.tabBar.count()):
|
||||||
widget = self.tabPlaylist.widget(idx)
|
widget = self.playlist_section.tabPlaylist.widget(idx)
|
||||||
if (
|
if (
|
||||||
track_sequence.next
|
track_sequence.next
|
||||||
and set_next
|
and set_next
|
||||||
and widget.playlist_id == track_sequence.next.playlist_id
|
and widget.playlist_id == track_sequence.next.playlist_id
|
||||||
):
|
):
|
||||||
self.tabPlaylist.setTabIcon(idx, QIcon(Config.PLAYLIST_ICON_NEXT))
|
self.playlist_section.tabPlaylist.setTabIcon(
|
||||||
|
idx, QIcon(Config.PLAYLIST_ICON_NEXT)
|
||||||
|
)
|
||||||
elif (
|
elif (
|
||||||
track_sequence.current
|
track_sequence.current
|
||||||
and widget.playlist_id == track_sequence.current.playlist_id
|
and widget.playlist_id == track_sequence.current.playlist_id
|
||||||
):
|
):
|
||||||
self.tabPlaylist.setTabIcon(idx, QIcon(Config.PLAYLIST_ICON_CURRENT))
|
self.playlist_section.tabPlaylist.setTabIcon(
|
||||||
|
idx, QIcon(Config.PLAYLIST_ICON_CURRENT)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.tabPlaylist.setTabIcon(idx, QIcon())
|
self.playlist_section.tabPlaylist.setTabIcon(idx, QIcon())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@ -497,7 +497,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return Qt.ItemFlag.ItemIsDropEnabled
|
return Qt.ItemFlag.NoItemFlags
|
||||||
|
|
||||||
default = (
|
default = (
|
||||||
Qt.ItemFlag.ItemIsEnabled
|
Qt.ItemFlag.ItemIsEnabled
|
||||||
|
|||||||
@ -22,10 +22,7 @@ from PyQt6.QtWidgets import (
|
|||||||
QFrame,
|
QFrame,
|
||||||
QMenu,
|
QMenu,
|
||||||
QMessageBox,
|
QMessageBox,
|
||||||
QProxyStyle,
|
|
||||||
QStyle,
|
|
||||||
QStyledItemDelegate,
|
QStyledItemDelegate,
|
||||||
QStyleOption,
|
|
||||||
QStyleOptionViewItem,
|
QStyleOptionViewItem,
|
||||||
QTableView,
|
QTableView,
|
||||||
QTableWidgetItem,
|
QTableWidgetItem,
|
||||||
@ -37,7 +34,7 @@ from PyQt6.QtWidgets import (
|
|||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
from audacity_controller import AudacityController
|
from audacity_controller import AudacityController
|
||||||
from classes import ApplicationError, Col, MusicMusterSignals, TrackInfo
|
from classes import ApplicationError, Col, MusicMusterSignals, PlaylistStyle, TrackInfo
|
||||||
from config import Config
|
from config import Config
|
||||||
from dialogs import TrackSelectDialog
|
from dialogs import TrackSelectDialog
|
||||||
from helpers import (
|
from helpers import (
|
||||||
@ -112,7 +109,7 @@ class PlaylistDelegate(QStyledItemDelegate):
|
|||||||
if self.current_editor:
|
if self.current_editor:
|
||||||
editor = self.current_editor
|
editor = self.current_editor
|
||||||
else:
|
else:
|
||||||
if index.column() == Col.INTRO.value:
|
if index.column() == QueryCol.INTRO.value:
|
||||||
editor = QDoubleSpinBox(parent)
|
editor = QDoubleSpinBox(parent)
|
||||||
editor.setDecimals(1)
|
editor.setDecimals(1)
|
||||||
editor.setSingleStep(0.1)
|
editor.setSingleStep(0.1)
|
||||||
@ -248,7 +245,7 @@ class PlaylistDelegate(QStyledItemDelegate):
|
|||||||
self.original_model_data = self.base_model.data(
|
self.original_model_data = self.base_model.data(
|
||||||
edit_index, Qt.ItemDataRole.EditRole
|
edit_index, Qt.ItemDataRole.EditRole
|
||||||
)
|
)
|
||||||
if index.column() == Col.INTRO.value:
|
if index.column() == QueryCol.INTRO.value:
|
||||||
if self.original_model_data.value():
|
if self.original_model_data.value():
|
||||||
editor.setValue(self.original_model_data.value() / 1000)
|
editor.setValue(self.original_model_data.value() / 1000)
|
||||||
else:
|
else:
|
||||||
@ -268,24 +265,6 @@ class PlaylistDelegate(QStyledItemDelegate):
|
|||||||
editor.setGeometry(option.rect)
|
editor.setGeometry(option.rect)
|
||||||
|
|
||||||
|
|
||||||
class PlaylistStyle(QProxyStyle):
|
|
||||||
def drawPrimitive(self, element, option, painter, widget=None):
|
|
||||||
"""
|
|
||||||
Draw a line across the entire row rather than just the column
|
|
||||||
we're hovering over.
|
|
||||||
"""
|
|
||||||
if (
|
|
||||||
element == QStyle.PrimitiveElement.PE_IndicatorItemViewItemDrop
|
|
||||||
and not option.rect.isNull()
|
|
||||||
):
|
|
||||||
option_new = QStyleOption(option)
|
|
||||||
option_new.rect.setLeft(0)
|
|
||||||
if widget:
|
|
||||||
option_new.rect.setRight(widget.width())
|
|
||||||
option = option_new
|
|
||||||
super().drawPrimitive(element, option, painter, widget)
|
|
||||||
|
|
||||||
|
|
||||||
class PlaylistTab(QTableView):
|
class PlaylistTab(QTableView):
|
||||||
"""
|
"""
|
||||||
The playlist view
|
The playlist view
|
||||||
|
|||||||
304
app/querylistmodel.py
Normal file
304
app/querylistmodel.py
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
# Standard library imports
|
||||||
|
# Allow forward reference to PlaylistModel
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import cast
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
|
# PyQt imports
|
||||||
|
from PyQt6.QtCore import (
|
||||||
|
QAbstractTableModel,
|
||||||
|
QModelIndex,
|
||||||
|
QRegularExpression,
|
||||||
|
QSortFilterProxyModel,
|
||||||
|
Qt,
|
||||||
|
QVariant,
|
||||||
|
)
|
||||||
|
from PyQt6.QtGui import (
|
||||||
|
QBrush,
|
||||||
|
QColor,
|
||||||
|
QFont,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Third party imports
|
||||||
|
|
||||||
|
# import snoop # type: ignore
|
||||||
|
|
||||||
|
# App imports
|
||||||
|
from classes import (
|
||||||
|
QueryCol,
|
||||||
|
)
|
||||||
|
from config import Config
|
||||||
|
from helpers import (
|
||||||
|
file_is_unreadable,
|
||||||
|
get_relative_date,
|
||||||
|
ms_to_mmss,
|
||||||
|
)
|
||||||
|
from log import log
|
||||||
|
from models import db, Playdates
|
||||||
|
from music_manager import RowAndTrack
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class QueryRow:
|
||||||
|
artist: str
|
||||||
|
bitrate: int
|
||||||
|
duration: int
|
||||||
|
lastplayed: dt.datetime
|
||||||
|
path: str
|
||||||
|
title: str
|
||||||
|
track_id: int
|
||||||
|
|
||||||
|
|
||||||
|
class QuerylistModel(QAbstractTableModel):
|
||||||
|
"""
|
||||||
|
The Querylist Model
|
||||||
|
|
||||||
|
Used to support query lists. The underlying database is never
|
||||||
|
updated. We just present tracks that match a query and allow the user
|
||||||
|
to copy those to a playlist.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
playlist_id: int,
|
||||||
|
) -> None:
|
||||||
|
log.debug("QuerylistModel.__init__()")
|
||||||
|
|
||||||
|
self.playlist_id = playlist_id
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.querylist_rows: dict[int, QueryRow] = {}
|
||||||
|
self._selected_rows: set[int] = set()
|
||||||
|
|
||||||
|
with db.Session() as session:
|
||||||
|
# Populate self.playlist_rows
|
||||||
|
self.load_data(session)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return (
|
||||||
|
f"<QuerylistModel: playlist_id={self.playlist_id}, {self.rowCount()} rows>"
|
||||||
|
)
|
||||||
|
|
||||||
|
def background_role(self, row: int, column: int, qrow: QueryRow) -> QVariant:
|
||||||
|
"""Return background setting"""
|
||||||
|
|
||||||
|
# Unreadable track file
|
||||||
|
if file_is_unreadable(qrow.path):
|
||||||
|
return QVariant(QColor(Config.COLOUR_UNREADABLE))
|
||||||
|
|
||||||
|
# Selected row
|
||||||
|
if row in self._selected_rows:
|
||||||
|
return QVariant(QColor(Config.COLOUR_QUERYLIST_SELECTED))
|
||||||
|
|
||||||
|
# Individual cell colouring
|
||||||
|
if column == QueryCol.BITRATE.value:
|
||||||
|
if not qrow.bitrate or qrow.bitrate < Config.BITRATE_LOW_THRESHOLD:
|
||||||
|
return QVariant(QColor(Config.COLOUR_BITRATE_LOW))
|
||||||
|
elif qrow.bitrate < Config.BITRATE_OK_THRESHOLD:
|
||||||
|
return QVariant(QColor(Config.COLOUR_BITRATE_MEDIUM))
|
||||||
|
else:
|
||||||
|
return QVariant(QColor(Config.COLOUR_BITRATE_OK))
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
|
||||||
|
"""Standard function for view"""
|
||||||
|
|
||||||
|
return len(QueryCol)
|
||||||
|
|
||||||
|
def data(
|
||||||
|
self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole
|
||||||
|
) -> QVariant:
|
||||||
|
"""Return data to view"""
|
||||||
|
|
||||||
|
if not index.isValid() or not (0 <= index.row() < len(self.querylist_rows)):
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
row = index.row()
|
||||||
|
column = index.column()
|
||||||
|
# rat for playlist row data as it's used a lot
|
||||||
|
qrow = self.querylist_rows[row]
|
||||||
|
|
||||||
|
# Dispatch to role-specific functions
|
||||||
|
dispatch_table: dict[int, Callable] = {
|
||||||
|
int(Qt.ItemDataRole.BackgroundRole): self.background_role,
|
||||||
|
int(Qt.ItemDataRole.DisplayRole): self.display_role,
|
||||||
|
int(Qt.ItemDataRole.ToolTipRole): self.tooltip_role,
|
||||||
|
}
|
||||||
|
|
||||||
|
if role in dispatch_table:
|
||||||
|
return QVariant(dispatch_table[role](row, column, qrow))
|
||||||
|
|
||||||
|
# Document other roles but don't use them
|
||||||
|
if role in [
|
||||||
|
Qt.ItemDataRole.DecorationRole,
|
||||||
|
Qt.ItemDataRole.EditRole,
|
||||||
|
Qt.ItemDataRole.FontRole,
|
||||||
|
Qt.ItemDataRole.ForegroundRole,
|
||||||
|
Qt.ItemDataRole.InitialSortOrderRole,
|
||||||
|
Qt.ItemDataRole.SizeHintRole,
|
||||||
|
Qt.ItemDataRole.StatusTipRole,
|
||||||
|
Qt.ItemDataRole.TextAlignmentRole,
|
||||||
|
Qt.ItemDataRole.ToolTipRole,
|
||||||
|
Qt.ItemDataRole.WhatsThisRole,
|
||||||
|
]:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
# Fall through to no-op
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def display_role(self, row: int, column: int, qrow: QueryRow) -> QVariant:
|
||||||
|
"""
|
||||||
|
Return text for display
|
||||||
|
"""
|
||||||
|
|
||||||
|
dispatch_table = {
|
||||||
|
QueryCol.ARTIST.value: QVariant(qrow.artist),
|
||||||
|
QueryCol.BITRATE.value: QVariant(qrow.bitrate),
|
||||||
|
QueryCol.DURATION.value: QVariant(ms_to_mmss(qrow.duration)),
|
||||||
|
QueryCol.LAST_PLAYED.value: QVariant(get_relative_date(qrow.lastplayed)),
|
||||||
|
QueryCol.TITLE.value: QVariant(qrow.title),
|
||||||
|
}
|
||||||
|
if column in dispatch_table:
|
||||||
|
return dispatch_table[column]
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
|
||||||
|
"""
|
||||||
|
Standard model flags
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not index.isValid():
|
||||||
|
return Qt.ItemFlag.NoItemFlags
|
||||||
|
|
||||||
|
return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable
|
||||||
|
|
||||||
|
def get_selected_track_ids(self) -> list[int]:
|
||||||
|
"""
|
||||||
|
Return a list of track_ids from selected tracks
|
||||||
|
"""
|
||||||
|
|
||||||
|
return [self.querylist_rows[row].track_id for row in self._selected_rows]
|
||||||
|
|
||||||
|
def headerData(
|
||||||
|
self,
|
||||||
|
section: int,
|
||||||
|
orientation: Qt.Orientation,
|
||||||
|
role: int = Qt.ItemDataRole.DisplayRole,
|
||||||
|
) -> QVariant:
|
||||||
|
"""
|
||||||
|
Return text for headers
|
||||||
|
"""
|
||||||
|
|
||||||
|
display_dispatch_table = {
|
||||||
|
QueryCol.TITLE.value: QVariant(Config.HEADER_TITLE),
|
||||||
|
QueryCol.ARTIST.value: QVariant(Config.HEADER_ARTIST),
|
||||||
|
QueryCol.DURATION.value: QVariant(Config.HEADER_DURATION),
|
||||||
|
QueryCol.LAST_PLAYED.value: QVariant(Config.HEADER_LAST_PLAYED),
|
||||||
|
QueryCol.BITRATE.value: QVariant(Config.HEADER_BITRATE),
|
||||||
|
}
|
||||||
|
|
||||||
|
if role == Qt.ItemDataRole.DisplayRole:
|
||||||
|
if orientation == Qt.Orientation.Horizontal:
|
||||||
|
return display_dispatch_table[section]
|
||||||
|
else:
|
||||||
|
if Config.ROWS_FROM_ZERO:
|
||||||
|
return QVariant(str(section))
|
||||||
|
else:
|
||||||
|
return QVariant(str(section + 1))
|
||||||
|
|
||||||
|
elif role == Qt.ItemDataRole.FontRole:
|
||||||
|
boldfont = QFont()
|
||||||
|
boldfont.setBold(True)
|
||||||
|
return QVariant(boldfont)
|
||||||
|
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def load_data(
|
||||||
|
self,
|
||||||
|
session: db.session,
|
||||||
|
sql: str = """
|
||||||
|
SELECT
|
||||||
|
tracks.*,playdates.lastplayed
|
||||||
|
FROM
|
||||||
|
tracks,playdates
|
||||||
|
WHERE
|
||||||
|
playdates.track_id=tracks.id
|
||||||
|
AND tracks.path LIKE '%/Singles/p%'
|
||||||
|
GROUP BY
|
||||||
|
tracks.id
|
||||||
|
HAVING
|
||||||
|
MAX(playdates.lastplayed) < DATE_SUB(NOW(), INTERVAL 1 YEAR)
|
||||||
|
ORDER BY tracks.title
|
||||||
|
;
|
||||||
|
""",
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Load data from user-defined query. Can probably hard-code the SELECT part
|
||||||
|
to ensure the required fields are returned.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# TODO: Move the SQLAlchemy parts to models later, but for now as proof
|
||||||
|
# of concept we'll keep it here.
|
||||||
|
|
||||||
|
from sqlalchemy import text
|
||||||
|
|
||||||
|
# Clear any exsiting rows
|
||||||
|
self.querylist_rows = {}
|
||||||
|
row = 0
|
||||||
|
|
||||||
|
results = session.execute(text(sql)).mappings().all()
|
||||||
|
for result in results:
|
||||||
|
queryrow = QueryRow(
|
||||||
|
artist=result["artist"],
|
||||||
|
bitrate=result["bitrate"],
|
||||||
|
duration=result["duration"],
|
||||||
|
lastplayed=result["lastplayed"],
|
||||||
|
path=result["path"],
|
||||||
|
title=result["title"],
|
||||||
|
track_id=result["id"],
|
||||||
|
)
|
||||||
|
self.querylist_rows[row] = queryrow
|
||||||
|
row += 1
|
||||||
|
|
||||||
|
def rowCount(self, index: QModelIndex = QModelIndex()) -> int:
|
||||||
|
"""Standard function for view"""
|
||||||
|
|
||||||
|
return len(self.querylist_rows)
|
||||||
|
|
||||||
|
def toggle_row_selection(self, row: int) -> None:
|
||||||
|
if row in self._selected_rows:
|
||||||
|
self._selected_rows.discard(row)
|
||||||
|
else:
|
||||||
|
self._selected_rows.add(row)
|
||||||
|
|
||||||
|
# Emit dataChanged for the entire row
|
||||||
|
top_left = self.index(row, 0)
|
||||||
|
bottom_right = self.index(row, self.columnCount() - 1)
|
||||||
|
self.dataChanged.emit(top_left, bottom_right, [Qt.ItemDataRole.BackgroundRole])
|
||||||
|
|
||||||
|
def tooltip_role(self, row: int, column: int, rat: RowAndTrack) -> QVariant:
|
||||||
|
"""
|
||||||
|
Return tooltip. Currently only used for last_played column.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if column != QueryCol.LAST_PLAYED.value:
|
||||||
|
return QVariant()
|
||||||
|
with db.Session() as session:
|
||||||
|
track_id = self.querylist_rows[row].track_id
|
||||||
|
if not track_id:
|
||||||
|
return QVariant()
|
||||||
|
playdates = Playdates.last_playdates(session, track_id)
|
||||||
|
return QVariant(
|
||||||
|
"<br>".join(
|
||||||
|
[
|
||||||
|
a.lastplayed.strftime(Config.LAST_PLAYED_TOOLTIP_DATE_FORMAT)
|
||||||
|
for a in reversed(playdates)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
193
app/querylists.py
Normal file
193
app/querylists.py
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
# Standard library imports
|
||||||
|
from typing import cast, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
|
# PyQt imports
|
||||||
|
from PyQt6.QtCore import (
|
||||||
|
QTimer,
|
||||||
|
)
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QAbstractItemView,
|
||||||
|
QTableView,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Third party imports
|
||||||
|
# import line_profiler
|
||||||
|
|
||||||
|
# App imports
|
||||||
|
from audacity_controller import AudacityController
|
||||||
|
from classes import ApplicationError, MusicMusterSignals, PlaylistStyle
|
||||||
|
from config import Config
|
||||||
|
from helpers import (
|
||||||
|
show_warning,
|
||||||
|
)
|
||||||
|
from log import log
|
||||||
|
from models import db, Settings
|
||||||
|
from querylistmodel import QuerylistModel
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from musicmuster import Window
|
||||||
|
|
||||||
|
|
||||||
|
class QuerylistTab(QTableView):
|
||||||
|
"""
|
||||||
|
The querylist view
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, musicmuster: "Window", model: QuerylistModel) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
# Save passed settings
|
||||||
|
self.musicmuster = musicmuster
|
||||||
|
|
||||||
|
self.playlist_id = model.playlist_id
|
||||||
|
|
||||||
|
# Set up widget
|
||||||
|
self.setAlternatingRowColors(True)
|
||||||
|
self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
|
||||||
|
|
||||||
|
# Set our custom style - this draws the drop indicator across the whole row
|
||||||
|
self.setStyle(PlaylistStyle())
|
||||||
|
|
||||||
|
# We will enable dragging when rows are selected. Disabling it
|
||||||
|
# here means we can click and drag to select rows.
|
||||||
|
self.setDragEnabled(False)
|
||||||
|
|
||||||
|
# Connect signals
|
||||||
|
self.signals = MusicMusterSignals()
|
||||||
|
self.signals.resize_rows_signal.connect(self.resize_rows)
|
||||||
|
|
||||||
|
# Selection model
|
||||||
|
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
|
||||||
|
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||||
|
|
||||||
|
# Enable item editing for checkboxes
|
||||||
|
self.clicked.connect(self.handle_row_click)
|
||||||
|
|
||||||
|
# Set up for Audacity
|
||||||
|
try:
|
||||||
|
self.ac: Optional[AudacityController] = AudacityController()
|
||||||
|
except ApplicationError as e:
|
||||||
|
self.ac = None
|
||||||
|
show_warning(self.musicmuster, "Audacity error", str(e))
|
||||||
|
|
||||||
|
# Load model, set column widths
|
||||||
|
self.setModel(model)
|
||||||
|
self._set_column_widths()
|
||||||
|
|
||||||
|
# Stretch last column *after* setting column widths which is
|
||||||
|
# *much* faster
|
||||||
|
h_header = self.horizontalHeader()
|
||||||
|
if h_header:
|
||||||
|
h_header.sectionResized.connect(self._column_resize)
|
||||||
|
h_header.setStretchLastSection(True)
|
||||||
|
# Resize on vertical header click
|
||||||
|
v_header = self.verticalHeader()
|
||||||
|
if v_header:
|
||||||
|
v_header.setMinimumSectionSize(5)
|
||||||
|
v_header.sectionHandleDoubleClicked.disconnect()
|
||||||
|
v_header.sectionHandleDoubleClicked.connect(self.resizeRowToContents)
|
||||||
|
|
||||||
|
# Setting ResizeToContents causes screen flash on load
|
||||||
|
self.resize_rows()
|
||||||
|
|
||||||
|
# ########## Overridden class functions ##########
|
||||||
|
|
||||||
|
def resizeRowToContents(self, row):
|
||||||
|
super().resizeRowToContents(row)
|
||||||
|
self.verticalHeader().resizeSection(row, self.sizeHintForRow(row))
|
||||||
|
|
||||||
|
def resizeRowsToContents(self):
|
||||||
|
header = self.verticalHeader()
|
||||||
|
for row in range(self.model().rowCount()):
|
||||||
|
hint = self.sizeHintForRow(row)
|
||||||
|
header.resizeSection(row, hint)
|
||||||
|
|
||||||
|
# ########## Custom functions ##########
|
||||||
|
def clear_selection(self) -> None:
|
||||||
|
"""Unselect all tracks and reset drag mode"""
|
||||||
|
|
||||||
|
self.clearSelection()
|
||||||
|
# We want to remove the focus from any widget otherwise keyboard
|
||||||
|
# activity may edit a cell.
|
||||||
|
fw = self.musicmuster.focusWidget()
|
||||||
|
if fw:
|
||||||
|
fw.clearFocus()
|
||||||
|
self.setDragEnabled(False)
|
||||||
|
|
||||||
|
def _column_resize(self, column_number: int, _old: int, _new: int) -> None:
|
||||||
|
"""
|
||||||
|
Called when column width changes. Save new width to database.
|
||||||
|
"""
|
||||||
|
|
||||||
|
log.debug(f"_column_resize({column_number=}, {_old=}, {_new=}")
|
||||||
|
|
||||||
|
header = self.horizontalHeader()
|
||||||
|
if not header:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Resize rows if necessary
|
||||||
|
self.resizeRowsToContents()
|
||||||
|
|
||||||
|
with db.Session() as session:
|
||||||
|
attr_name = f"querylist_col_{column_number}_width"
|
||||||
|
record = Settings.get_setting(session, attr_name)
|
||||||
|
record.f_int = self.columnWidth(column_number)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
def handle_row_click(self, index):
|
||||||
|
self.model().toggle_row_selection(index.row())
|
||||||
|
self.clearSelection()
|
||||||
|
|
||||||
|
def model(self) -> QuerylistModel:
|
||||||
|
"""
|
||||||
|
Override return type to keep mypy happy in this module
|
||||||
|
"""
|
||||||
|
|
||||||
|
return cast(QuerylistModel, super().model())
|
||||||
|
|
||||||
|
def resize_rows(self, playlist_id: Optional[int] = None) -> None:
|
||||||
|
"""
|
||||||
|
If playlist_id is us, resize rows
|
||||||
|
"""
|
||||||
|
|
||||||
|
log.debug(f"resize_rows({playlist_id=}) {self.playlist_id=}")
|
||||||
|
|
||||||
|
if playlist_id and playlist_id != self.playlist_id:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Suggestion from phind.com
|
||||||
|
def resize_row(row, count=1):
|
||||||
|
row_count = self.model().rowCount()
|
||||||
|
for todo in range(count):
|
||||||
|
if row < row_count:
|
||||||
|
self.resizeRowToContents(row)
|
||||||
|
row += 1
|
||||||
|
if row < row_count:
|
||||||
|
QTimer.singleShot(0, lambda: resize_row(row, count))
|
||||||
|
|
||||||
|
# Start resizing from row 0, 10 rows at a time
|
||||||
|
QTimer.singleShot(0, lambda: resize_row(0, Config.RESIZE_ROW_CHUNK_SIZE))
|
||||||
|
|
||||||
|
def _set_column_widths(self) -> None:
|
||||||
|
"""Column widths from settings"""
|
||||||
|
|
||||||
|
log.debug("_set_column_widths()")
|
||||||
|
|
||||||
|
header = self.horizontalHeader()
|
||||||
|
if not header:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Last column is set to stretch so ignore it here
|
||||||
|
with db.Session() as session:
|
||||||
|
for column_number in range(header.count() - 1):
|
||||||
|
attr_name = f"querylist_col_{column_number}_width"
|
||||||
|
record = Settings.get_setting(session, attr_name)
|
||||||
|
if record.f_int is not None:
|
||||||
|
self.setColumnWidth(column_number, record.f_int)
|
||||||
|
else:
|
||||||
|
self.setColumnWidth(column_number, Config.DEFAULT_COLUMN_WIDTH)
|
||||||
|
|
||||||
|
def tab_live(self) -> None:
|
||||||
|
"""Noop for query tabs"""
|
||||||
|
|
||||||
|
return
|
||||||
@ -997,6 +997,9 @@ padding-left: 8px;</string>
|
|||||||
<addaction name="actionRenamePlaylist"/>
|
<addaction name="actionRenamePlaylist"/>
|
||||||
<addaction name="actionDeletePlaylist"/>
|
<addaction name="actionDeletePlaylist"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionOpenQuerylist"/>
|
||||||
|
<addaction name="actionManage_querylists"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
<addaction name="actionSave_as_template"/>
|
<addaction name="actionSave_as_template"/>
|
||||||
<addaction name="actionManage_templates"/>
|
<addaction name="actionManage_templates"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
@ -1140,7 +1143,7 @@ padding-left: 8px;</string>
|
|||||||
</action>
|
</action>
|
||||||
<action name="actionOpenPlaylist">
|
<action name="actionOpenPlaylist">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>O&pen...</string>
|
<string>Open &playlist...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionNewPlaylist">
|
<action name="actionNewPlaylist">
|
||||||
@ -1369,6 +1372,16 @@ padding-left: 8px;</string>
|
|||||||
<string>Import files...</string>
|
<string>Import files...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionOpenQuerylist">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open &querylist...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionManage_querylists">
|
||||||
|
<property name="text">
|
||||||
|
<string>Manage querylists...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|||||||
589
app/ui/main_window_footer.ui
Normal file
589
app/ui/main_window_footer.ui
Normal file
@ -0,0 +1,589 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>FooterSection</class>
|
||||||
|
<widget class="QWidget" name="FooterSection">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1237</width>
|
||||||
|
<height>154</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="InfoFooterFrame">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: rgb(192, 191, 188)</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="FadeStopInfoFrame">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>152</width>
|
||||||
|
<height>112</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>184</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnPreview">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>132</width>
|
||||||
|
<height>41</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string> Preview</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons.qrc">
|
||||||
|
<normaloff>:/icons/headphones</normaloff>:/icons/headphones</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>30</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBoxIntroControls">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>132</width>
|
||||||
|
<height>46</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>132</width>
|
||||||
|
<height>46</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<widget class="QPushButton" name="btnPreviewStart">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string><<</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="btnPreviewArm">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>44</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons.qrc">
|
||||||
|
<normaloff>:/icons/record-button.png</normaloff>
|
||||||
|
<normalon>:/icons/record-red-button.png</normalon>:/icons/record-button.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="btnPreviewEnd">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>88</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>>></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="btnPreviewBack">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>23</y>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string><</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="btnPreviewMark">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>44</x>
|
||||||
|
<y>23</y>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normalon>:/icons/star.png</normalon>
|
||||||
|
<disabledoff>:/icons/star_empty.png</disabledoff>
|
||||||
|
</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="btnPreviewFwd">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>88</x>
|
||||||
|
<y>23</y>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>44</width>
|
||||||
|
<height>23</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_intro">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>152</width>
|
||||||
|
<height>112</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Intro</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_intro_timer">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>FreeSans</family>
|
||||||
|
<pointsize>40</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>0:0</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_toggleplayed_3db">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>152</width>
|
||||||
|
<height>112</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>184</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnDrop3db">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>132</width>
|
||||||
|
<height>41</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>164</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>-3dB to talk</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnHidePlayed">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>132</width>
|
||||||
|
<height>41</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>164</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Hide played</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_fade">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>152</width>
|
||||||
|
<height>112</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Fade</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_fade_timer">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>FreeSans</family>
|
||||||
|
<pointsize>40</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>00:00</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_silent">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>152</width>
|
||||||
|
<height>112</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Silent</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_silent_timer">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>FreeSans</family>
|
||||||
|
<pointsize>40</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>00:00</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="PlotWidget" name="widgetFadeVolume" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>1</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>151</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>151</width>
|
||||||
|
<height>112</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnFade">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>132</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>164</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string> Fade</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons.qrc">
|
||||||
|
<normaloff>:/icons/fade</normaloff>:/icons/fade</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>30</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnStop">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>36</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string> Stop</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="icons.qrc">
|
||||||
|
<normaloff>:/icons/stopsign</normaloff>:/icons/stopsign</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>PlotWidget</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>pyqtgraph</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="icons.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
274
app/ui/main_window_footer_ui.py
Normal file
274
app/ui/main_window_footer_ui.py
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
# Form implementation generated from reading ui file 'app/ui/main_window_footer.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt6 UI code generator 6.8.1
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_FooterSection(object):
|
||||||
|
def setupUi(self, FooterSection):
|
||||||
|
FooterSection.setObjectName("FooterSection")
|
||||||
|
FooterSection.resize(1237, 154)
|
||||||
|
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(FooterSection)
|
||||||
|
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||||
|
self.InfoFooterFrame = QtWidgets.QFrame(parent=FooterSection)
|
||||||
|
self.InfoFooterFrame.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
||||||
|
self.InfoFooterFrame.setStyleSheet("background-color: rgb(192, 191, 188)")
|
||||||
|
self.InfoFooterFrame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||||
|
self.InfoFooterFrame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||||
|
self.InfoFooterFrame.setObjectName("InfoFooterFrame")
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(self.InfoFooterFrame)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.FadeStopInfoFrame = QtWidgets.QFrame(parent=self.InfoFooterFrame)
|
||||||
|
self.FadeStopInfoFrame.setMinimumSize(QtCore.QSize(152, 112))
|
||||||
|
self.FadeStopInfoFrame.setMaximumSize(QtCore.QSize(184, 16777215))
|
||||||
|
self.FadeStopInfoFrame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||||
|
self.FadeStopInfoFrame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||||
|
self.FadeStopInfoFrame.setObjectName("FadeStopInfoFrame")
|
||||||
|
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.FadeStopInfoFrame)
|
||||||
|
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||||
|
self.btnPreview = QtWidgets.QPushButton(parent=self.FadeStopInfoFrame)
|
||||||
|
self.btnPreview.setMinimumSize(QtCore.QSize(132, 41))
|
||||||
|
icon = QtGui.QIcon()
|
||||||
|
icon.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/headphones"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
|
self.btnPreview.setIcon(icon)
|
||||||
|
self.btnPreview.setIconSize(QtCore.QSize(30, 30))
|
||||||
|
self.btnPreview.setCheckable(True)
|
||||||
|
self.btnPreview.setObjectName("btnPreview")
|
||||||
|
self.verticalLayout_4.addWidget(self.btnPreview)
|
||||||
|
self.groupBoxIntroControls = QtWidgets.QGroupBox(parent=self.FadeStopInfoFrame)
|
||||||
|
self.groupBoxIntroControls.setMinimumSize(QtCore.QSize(132, 46))
|
||||||
|
self.groupBoxIntroControls.setMaximumSize(QtCore.QSize(132, 46))
|
||||||
|
self.groupBoxIntroControls.setTitle("")
|
||||||
|
self.groupBoxIntroControls.setObjectName("groupBoxIntroControls")
|
||||||
|
self.btnPreviewStart = QtWidgets.QPushButton(parent=self.groupBoxIntroControls)
|
||||||
|
self.btnPreviewStart.setGeometry(QtCore.QRect(0, 0, 44, 23))
|
||||||
|
self.btnPreviewStart.setMinimumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewStart.setMaximumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewStart.setObjectName("btnPreviewStart")
|
||||||
|
self.btnPreviewArm = QtWidgets.QPushButton(parent=self.groupBoxIntroControls)
|
||||||
|
self.btnPreviewArm.setGeometry(QtCore.QRect(44, 0, 44, 23))
|
||||||
|
self.btnPreviewArm.setMinimumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewArm.setMaximumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewArm.setText("")
|
||||||
|
icon1 = QtGui.QIcon()
|
||||||
|
icon1.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/record-button.png"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
|
icon1.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/record-red-button.png"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.On,
|
||||||
|
)
|
||||||
|
self.btnPreviewArm.setIcon(icon1)
|
||||||
|
self.btnPreviewArm.setCheckable(True)
|
||||||
|
self.btnPreviewArm.setObjectName("btnPreviewArm")
|
||||||
|
self.btnPreviewEnd = QtWidgets.QPushButton(parent=self.groupBoxIntroControls)
|
||||||
|
self.btnPreviewEnd.setGeometry(QtCore.QRect(88, 0, 44, 23))
|
||||||
|
self.btnPreviewEnd.setMinimumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewEnd.setMaximumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewEnd.setObjectName("btnPreviewEnd")
|
||||||
|
self.btnPreviewBack = QtWidgets.QPushButton(parent=self.groupBoxIntroControls)
|
||||||
|
self.btnPreviewBack.setGeometry(QtCore.QRect(0, 23, 44, 23))
|
||||||
|
self.btnPreviewBack.setMinimumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewBack.setMaximumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewBack.setObjectName("btnPreviewBack")
|
||||||
|
self.btnPreviewMark = QtWidgets.QPushButton(parent=self.groupBoxIntroControls)
|
||||||
|
self.btnPreviewMark.setEnabled(False)
|
||||||
|
self.btnPreviewMark.setGeometry(QtCore.QRect(44, 23, 44, 23))
|
||||||
|
self.btnPreviewMark.setMinimumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewMark.setMaximumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewMark.setText("")
|
||||||
|
icon2 = QtGui.QIcon()
|
||||||
|
icon2.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/star.png"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.On,
|
||||||
|
)
|
||||||
|
icon2.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/star_empty.png"),
|
||||||
|
QtGui.QIcon.Mode.Disabled,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
|
self.btnPreviewMark.setIcon(icon2)
|
||||||
|
self.btnPreviewMark.setObjectName("btnPreviewMark")
|
||||||
|
self.btnPreviewFwd = QtWidgets.QPushButton(parent=self.groupBoxIntroControls)
|
||||||
|
self.btnPreviewFwd.setGeometry(QtCore.QRect(88, 23, 44, 23))
|
||||||
|
self.btnPreviewFwd.setMinimumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewFwd.setMaximumSize(QtCore.QSize(44, 23))
|
||||||
|
self.btnPreviewFwd.setObjectName("btnPreviewFwd")
|
||||||
|
self.verticalLayout_4.addWidget(self.groupBoxIntroControls)
|
||||||
|
self.horizontalLayout.addWidget(self.FadeStopInfoFrame)
|
||||||
|
self.frame_intro = QtWidgets.QFrame(parent=self.InfoFooterFrame)
|
||||||
|
self.frame_intro.setMinimumSize(QtCore.QSize(152, 112))
|
||||||
|
self.frame_intro.setStyleSheet("")
|
||||||
|
self.frame_intro.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||||
|
self.frame_intro.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||||
|
self.frame_intro.setObjectName("frame_intro")
|
||||||
|
self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.frame_intro)
|
||||||
|
self.verticalLayout_9.setObjectName("verticalLayout_9")
|
||||||
|
self.label_7 = QtWidgets.QLabel(parent=self.frame_intro)
|
||||||
|
self.label_7.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.label_7.setObjectName("label_7")
|
||||||
|
self.verticalLayout_9.addWidget(self.label_7)
|
||||||
|
self.label_intro_timer = QtWidgets.QLabel(parent=self.frame_intro)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("FreeSans")
|
||||||
|
font.setPointSize(40)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.label_intro_timer.setFont(font)
|
||||||
|
self.label_intro_timer.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.label_intro_timer.setObjectName("label_intro_timer")
|
||||||
|
self.verticalLayout_9.addWidget(self.label_intro_timer)
|
||||||
|
self.horizontalLayout.addWidget(self.frame_intro)
|
||||||
|
self.frame_toggleplayed_3db = QtWidgets.QFrame(parent=self.InfoFooterFrame)
|
||||||
|
self.frame_toggleplayed_3db.setMinimumSize(QtCore.QSize(152, 112))
|
||||||
|
self.frame_toggleplayed_3db.setMaximumSize(QtCore.QSize(184, 16777215))
|
||||||
|
self.frame_toggleplayed_3db.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||||
|
self.frame_toggleplayed_3db.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||||
|
self.frame_toggleplayed_3db.setObjectName("frame_toggleplayed_3db")
|
||||||
|
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.frame_toggleplayed_3db)
|
||||||
|
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||||
|
self.btnDrop3db = QtWidgets.QPushButton(parent=self.frame_toggleplayed_3db)
|
||||||
|
self.btnDrop3db.setMinimumSize(QtCore.QSize(132, 41))
|
||||||
|
self.btnDrop3db.setMaximumSize(QtCore.QSize(164, 16777215))
|
||||||
|
self.btnDrop3db.setCheckable(True)
|
||||||
|
self.btnDrop3db.setObjectName("btnDrop3db")
|
||||||
|
self.verticalLayout_6.addWidget(self.btnDrop3db)
|
||||||
|
self.btnHidePlayed = QtWidgets.QPushButton(parent=self.frame_toggleplayed_3db)
|
||||||
|
self.btnHidePlayed.setMinimumSize(QtCore.QSize(132, 41))
|
||||||
|
self.btnHidePlayed.setMaximumSize(QtCore.QSize(164, 16777215))
|
||||||
|
self.btnHidePlayed.setCheckable(True)
|
||||||
|
self.btnHidePlayed.setObjectName("btnHidePlayed")
|
||||||
|
self.verticalLayout_6.addWidget(self.btnHidePlayed)
|
||||||
|
self.horizontalLayout.addWidget(self.frame_toggleplayed_3db)
|
||||||
|
self.frame_fade = QtWidgets.QFrame(parent=self.InfoFooterFrame)
|
||||||
|
self.frame_fade.setMinimumSize(QtCore.QSize(152, 112))
|
||||||
|
self.frame_fade.setStyleSheet("")
|
||||||
|
self.frame_fade.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||||
|
self.frame_fade.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||||
|
self.frame_fade.setObjectName("frame_fade")
|
||||||
|
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_fade)
|
||||||
|
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||||
|
self.label_4 = QtWidgets.QLabel(parent=self.frame_fade)
|
||||||
|
self.label_4.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.label_4.setObjectName("label_4")
|
||||||
|
self.verticalLayout_2.addWidget(self.label_4)
|
||||||
|
self.label_fade_timer = QtWidgets.QLabel(parent=self.frame_fade)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("FreeSans")
|
||||||
|
font.setPointSize(40)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.label_fade_timer.setFont(font)
|
||||||
|
self.label_fade_timer.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.label_fade_timer.setObjectName("label_fade_timer")
|
||||||
|
self.verticalLayout_2.addWidget(self.label_fade_timer)
|
||||||
|
self.horizontalLayout.addWidget(self.frame_fade)
|
||||||
|
self.frame_silent = QtWidgets.QFrame(parent=self.InfoFooterFrame)
|
||||||
|
self.frame_silent.setMinimumSize(QtCore.QSize(152, 112))
|
||||||
|
self.frame_silent.setStyleSheet("")
|
||||||
|
self.frame_silent.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||||
|
self.frame_silent.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||||
|
self.frame_silent.setObjectName("frame_silent")
|
||||||
|
self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.frame_silent)
|
||||||
|
self.verticalLayout_7.setObjectName("verticalLayout_7")
|
||||||
|
self.label_5 = QtWidgets.QLabel(parent=self.frame_silent)
|
||||||
|
self.label_5.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.label_5.setObjectName("label_5")
|
||||||
|
self.verticalLayout_7.addWidget(self.label_5)
|
||||||
|
self.label_silent_timer = QtWidgets.QLabel(parent=self.frame_silent)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("FreeSans")
|
||||||
|
font.setPointSize(40)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.label_silent_timer.setFont(font)
|
||||||
|
self.label_silent_timer.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.label_silent_timer.setObjectName("label_silent_timer")
|
||||||
|
self.verticalLayout_7.addWidget(self.label_silent_timer)
|
||||||
|
self.horizontalLayout.addWidget(self.frame_silent)
|
||||||
|
self.widgetFadeVolume = PlotWidget(parent=self.InfoFooterFrame)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
)
|
||||||
|
sizePolicy.setHorizontalStretch(1)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(
|
||||||
|
self.widgetFadeVolume.sizePolicy().hasHeightForWidth()
|
||||||
|
)
|
||||||
|
self.widgetFadeVolume.setSizePolicy(sizePolicy)
|
||||||
|
self.widgetFadeVolume.setMinimumSize(QtCore.QSize(0, 0))
|
||||||
|
self.widgetFadeVolume.setObjectName("widgetFadeVolume")
|
||||||
|
self.horizontalLayout.addWidget(self.widgetFadeVolume)
|
||||||
|
self.frame = QtWidgets.QFrame(parent=self.InfoFooterFrame)
|
||||||
|
self.frame.setMinimumSize(QtCore.QSize(151, 0))
|
||||||
|
self.frame.setMaximumSize(QtCore.QSize(151, 112))
|
||||||
|
self.frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||||
|
self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||||
|
self.frame.setObjectName("frame")
|
||||||
|
self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.frame)
|
||||||
|
self.verticalLayout_5.setObjectName("verticalLayout_5")
|
||||||
|
self.btnFade = QtWidgets.QPushButton(parent=self.frame)
|
||||||
|
self.btnFade.setMinimumSize(QtCore.QSize(132, 32))
|
||||||
|
self.btnFade.setMaximumSize(QtCore.QSize(164, 16777215))
|
||||||
|
icon3 = QtGui.QIcon()
|
||||||
|
icon3.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/fade"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
|
self.btnFade.setIcon(icon3)
|
||||||
|
self.btnFade.setIconSize(QtCore.QSize(30, 30))
|
||||||
|
self.btnFade.setObjectName("btnFade")
|
||||||
|
self.verticalLayout_5.addWidget(self.btnFade)
|
||||||
|
self.btnStop = QtWidgets.QPushButton(parent=self.frame)
|
||||||
|
self.btnStop.setMinimumSize(QtCore.QSize(0, 36))
|
||||||
|
icon4 = QtGui.QIcon()
|
||||||
|
icon4.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/stopsign"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
|
self.btnStop.setIcon(icon4)
|
||||||
|
self.btnStop.setObjectName("btnStop")
|
||||||
|
self.verticalLayout_5.addWidget(self.btnStop)
|
||||||
|
self.horizontalLayout.addWidget(self.frame)
|
||||||
|
self.horizontalLayout_2.addWidget(self.InfoFooterFrame)
|
||||||
|
|
||||||
|
self.retranslateUi(FooterSection)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(FooterSection)
|
||||||
|
|
||||||
|
def retranslateUi(self, FooterSection):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
FooterSection.setWindowTitle(_translate("FooterSection", "Form"))
|
||||||
|
self.btnPreview.setText(_translate("FooterSection", " Preview"))
|
||||||
|
self.btnPreviewStart.setText(_translate("FooterSection", "<<"))
|
||||||
|
self.btnPreviewEnd.setText(_translate("FooterSection", ">>"))
|
||||||
|
self.btnPreviewBack.setText(_translate("FooterSection", "<"))
|
||||||
|
self.btnPreviewFwd.setText(_translate("FooterSection", ">"))
|
||||||
|
self.label_7.setText(_translate("FooterSection", "Intro"))
|
||||||
|
self.label_intro_timer.setText(_translate("FooterSection", "0:0"))
|
||||||
|
self.btnDrop3db.setText(_translate("FooterSection", "-3dB to talk"))
|
||||||
|
self.btnHidePlayed.setText(_translate("FooterSection", "Hide played"))
|
||||||
|
self.label_4.setText(_translate("FooterSection", "Fade"))
|
||||||
|
self.label_fade_timer.setText(_translate("FooterSection", "00:00"))
|
||||||
|
self.label_5.setText(_translate("FooterSection", "Silent"))
|
||||||
|
self.label_silent_timer.setText(_translate("FooterSection", "00:00"))
|
||||||
|
self.btnFade.setText(_translate("FooterSection", " Fade"))
|
||||||
|
self.btnStop.setText(_translate("FooterSection", " Stop"))
|
||||||
|
|
||||||
|
|
||||||
|
from pyqtgraph import PlotWidget # type: ignore
|
||||||
314
app/ui/main_window_header.ui
Normal file
314
app/ui/main_window_header.ui
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>HeaderSection</class>
|
||||||
|
<widget class="QWidget" name="HeaderSection">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1273</width>
|
||||||
|
<height>179</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="previous_track_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>230</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Sans</family>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: #f8d7da;
|
||||||
|
border: 1px solid rgb(85, 87, 83);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Last track:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="current_track_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>230</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Sans</family>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: #d4edda;
|
||||||
|
border: 1px solid rgb(85, 87, 83);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Current track:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="next_track_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>230</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Sans</family>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: #fff3cd;
|
||||||
|
border: 1px solid rgb(85, 87, 83);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Next track:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="hdrPreviousTrack">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Sans</family>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: #f8d7da;
|
||||||
|
border: 1px solid rgb(85, 87, 83);</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="hdrCurrentTrack">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: #d4edda;
|
||||||
|
border: 1px solid rgb(85, 87, 83);
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 8px;
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="hdrNextTrack">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>20</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: #fff3cd;
|
||||||
|
border: 1px solid rgb(85, 87, 83);
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 8px;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_2">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>131</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>230</width>
|
||||||
|
<height>131</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblTOD">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>208</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>35</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>00:00:00</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_elapsed_timer">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>FreeSans</family>
|
||||||
|
<pointsize>18</pointsize>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color: black;</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>00:00 / 00:00</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QFrame" name="frame_4">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>16</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="autoFillBackground">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: rgb(154, 153, 150)</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
178
app/ui/main_window_header_ui.py
Normal file
178
app/ui/main_window_header_ui.py
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
# Form implementation generated from reading ui file 'app/ui/main_window_header.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt6 UI code generator 6.8.1
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_HeaderSection(object):
|
||||||
|
def setupUi(self, HeaderSection):
|
||||||
|
HeaderSection.setObjectName("HeaderSection")
|
||||||
|
HeaderSection.resize(1273, 179)
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(HeaderSection)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.gridLayout = QtWidgets.QGridLayout()
|
||||||
|
self.gridLayout.setObjectName("gridLayout")
|
||||||
|
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
|
||||||
|
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||||
|
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
|
||||||
|
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||||
|
self.previous_track_2 = QtWidgets.QLabel(parent=HeaderSection)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.previous_track_2.sizePolicy().hasHeightForWidth())
|
||||||
|
self.previous_track_2.setSizePolicy(sizePolicy)
|
||||||
|
self.previous_track_2.setMaximumSize(QtCore.QSize(230, 16777215))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Sans")
|
||||||
|
font.setPointSize(20)
|
||||||
|
self.previous_track_2.setFont(font)
|
||||||
|
self.previous_track_2.setStyleSheet("background-color: #f8d7da;\n"
|
||||||
|
"border: 1px solid rgb(85, 87, 83);")
|
||||||
|
self.previous_track_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
|
||||||
|
self.previous_track_2.setObjectName("previous_track_2")
|
||||||
|
self.verticalLayout_3.addWidget(self.previous_track_2)
|
||||||
|
self.current_track_2 = QtWidgets.QLabel(parent=HeaderSection)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.current_track_2.sizePolicy().hasHeightForWidth())
|
||||||
|
self.current_track_2.setSizePolicy(sizePolicy)
|
||||||
|
self.current_track_2.setMaximumSize(QtCore.QSize(230, 16777215))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Sans")
|
||||||
|
font.setPointSize(20)
|
||||||
|
self.current_track_2.setFont(font)
|
||||||
|
self.current_track_2.setStyleSheet("background-color: #d4edda;\n"
|
||||||
|
"border: 1px solid rgb(85, 87, 83);")
|
||||||
|
self.current_track_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
|
||||||
|
self.current_track_2.setObjectName("current_track_2")
|
||||||
|
self.verticalLayout_3.addWidget(self.current_track_2)
|
||||||
|
self.next_track_2 = QtWidgets.QLabel(parent=HeaderSection)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.next_track_2.sizePolicy().hasHeightForWidth())
|
||||||
|
self.next_track_2.setSizePolicy(sizePolicy)
|
||||||
|
self.next_track_2.setMaximumSize(QtCore.QSize(230, 16777215))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Sans")
|
||||||
|
font.setPointSize(20)
|
||||||
|
self.next_track_2.setFont(font)
|
||||||
|
self.next_track_2.setStyleSheet("background-color: #fff3cd;\n"
|
||||||
|
"border: 1px solid rgb(85, 87, 83);")
|
||||||
|
self.next_track_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
|
||||||
|
self.next_track_2.setObjectName("next_track_2")
|
||||||
|
self.verticalLayout_3.addWidget(self.next_track_2)
|
||||||
|
self.horizontalLayout_3.addLayout(self.verticalLayout_3)
|
||||||
|
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||||
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
|
self.hdrPreviousTrack = QtWidgets.QLabel(parent=HeaderSection)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.hdrPreviousTrack.sizePolicy().hasHeightForWidth())
|
||||||
|
self.hdrPreviousTrack.setSizePolicy(sizePolicy)
|
||||||
|
self.hdrPreviousTrack.setMinimumSize(QtCore.QSize(0, 0))
|
||||||
|
self.hdrPreviousTrack.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Sans")
|
||||||
|
font.setPointSize(20)
|
||||||
|
self.hdrPreviousTrack.setFont(font)
|
||||||
|
self.hdrPreviousTrack.setStyleSheet("background-color: #f8d7da;\n"
|
||||||
|
"border: 1px solid rgb(85, 87, 83);")
|
||||||
|
self.hdrPreviousTrack.setText("")
|
||||||
|
self.hdrPreviousTrack.setWordWrap(False)
|
||||||
|
self.hdrPreviousTrack.setObjectName("hdrPreviousTrack")
|
||||||
|
self.verticalLayout.addWidget(self.hdrPreviousTrack)
|
||||||
|
self.hdrCurrentTrack = QtWidgets.QPushButton(parent=HeaderSection)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.hdrCurrentTrack.sizePolicy().hasHeightForWidth())
|
||||||
|
self.hdrCurrentTrack.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(20)
|
||||||
|
self.hdrCurrentTrack.setFont(font)
|
||||||
|
self.hdrCurrentTrack.setStyleSheet("background-color: #d4edda;\n"
|
||||||
|
"border: 1px solid rgb(85, 87, 83);\n"
|
||||||
|
"text-align: left;\n"
|
||||||
|
"padding-left: 8px;\n"
|
||||||
|
"")
|
||||||
|
self.hdrCurrentTrack.setText("")
|
||||||
|
self.hdrCurrentTrack.setFlat(True)
|
||||||
|
self.hdrCurrentTrack.setObjectName("hdrCurrentTrack")
|
||||||
|
self.verticalLayout.addWidget(self.hdrCurrentTrack)
|
||||||
|
self.hdrNextTrack = QtWidgets.QPushButton(parent=HeaderSection)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.hdrNextTrack.sizePolicy().hasHeightForWidth())
|
||||||
|
self.hdrNextTrack.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(20)
|
||||||
|
self.hdrNextTrack.setFont(font)
|
||||||
|
self.hdrNextTrack.setStyleSheet("background-color: #fff3cd;\n"
|
||||||
|
"border: 1px solid rgb(85, 87, 83);\n"
|
||||||
|
"text-align: left;\n"
|
||||||
|
"padding-left: 8px;")
|
||||||
|
self.hdrNextTrack.setText("")
|
||||||
|
self.hdrNextTrack.setFlat(True)
|
||||||
|
self.hdrNextTrack.setObjectName("hdrNextTrack")
|
||||||
|
self.verticalLayout.addWidget(self.hdrNextTrack)
|
||||||
|
self.horizontalLayout_3.addLayout(self.verticalLayout)
|
||||||
|
self.frame_2 = QtWidgets.QFrame(parent=HeaderSection)
|
||||||
|
self.frame_2.setMinimumSize(QtCore.QSize(0, 131))
|
||||||
|
self.frame_2.setMaximumSize(QtCore.QSize(230, 131))
|
||||||
|
self.frame_2.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||||
|
self.frame_2.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||||
|
self.frame_2.setObjectName("frame_2")
|
||||||
|
self.verticalLayout_10 = QtWidgets.QVBoxLayout(self.frame_2)
|
||||||
|
self.verticalLayout_10.setObjectName("verticalLayout_10")
|
||||||
|
self.lblTOD = QtWidgets.QLabel(parent=self.frame_2)
|
||||||
|
self.lblTOD.setMinimumSize(QtCore.QSize(208, 0))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(35)
|
||||||
|
self.lblTOD.setFont(font)
|
||||||
|
self.lblTOD.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.lblTOD.setObjectName("lblTOD")
|
||||||
|
self.verticalLayout_10.addWidget(self.lblTOD)
|
||||||
|
self.label_elapsed_timer = QtWidgets.QLabel(parent=self.frame_2)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("FreeSans")
|
||||||
|
font.setPointSize(18)
|
||||||
|
font.setBold(False)
|
||||||
|
font.setWeight(50)
|
||||||
|
self.label_elapsed_timer.setFont(font)
|
||||||
|
self.label_elapsed_timer.setStyleSheet("color: black;")
|
||||||
|
self.label_elapsed_timer.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.label_elapsed_timer.setObjectName("label_elapsed_timer")
|
||||||
|
self.verticalLayout_10.addWidget(self.label_elapsed_timer)
|
||||||
|
self.horizontalLayout_3.addWidget(self.frame_2)
|
||||||
|
self.gridLayout.addLayout(self.horizontalLayout_3, 0, 0, 1, 1)
|
||||||
|
self.frame_4 = QtWidgets.QFrame(parent=HeaderSection)
|
||||||
|
self.frame_4.setMinimumSize(QtCore.QSize(0, 16))
|
||||||
|
self.frame_4.setAutoFillBackground(False)
|
||||||
|
self.frame_4.setStyleSheet("background-color: rgb(154, 153, 150)")
|
||||||
|
self.frame_4.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
|
||||||
|
self.frame_4.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
|
||||||
|
self.frame_4.setObjectName("frame_4")
|
||||||
|
self.gridLayout.addWidget(self.frame_4, 1, 0, 1, 1)
|
||||||
|
self.horizontalLayout.addLayout(self.gridLayout)
|
||||||
|
|
||||||
|
self.retranslateUi(HeaderSection)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(HeaderSection)
|
||||||
|
|
||||||
|
def retranslateUi(self, HeaderSection):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
HeaderSection.setWindowTitle(_translate("HeaderSection", "Form"))
|
||||||
|
self.previous_track_2.setText(_translate("HeaderSection", "Last track:"))
|
||||||
|
self.current_track_2.setText(_translate("HeaderSection", "Current track:"))
|
||||||
|
self.next_track_2.setText(_translate("HeaderSection", "Next track:"))
|
||||||
|
self.lblTOD.setText(_translate("HeaderSection", "00:00:00"))
|
||||||
|
self.label_elapsed_timer.setText(_translate("HeaderSection", "00:00 / 00:00"))
|
||||||
42
app/ui/main_window_playlist.ui
Normal file
42
app/ui/main_window_playlist.ui
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>PlaylistSection</class>
|
||||||
|
<widget class="QWidget" name="PlaylistSection">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1249</width>
|
||||||
|
<height>499</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QTabWidget" name="tabPlaylist">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="documentMode">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tabsClosable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="movable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
34
app/ui/main_window_playlist_ui.py
Normal file
34
app/ui/main_window_playlist_ui.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Form implementation generated from reading ui file 'app/ui/main_window_playlist.ui'
|
||||||
|
#
|
||||||
|
# Created by: PyQt6 UI code generator 6.8.1
|
||||||
|
#
|
||||||
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
|
class Ui_PlaylistSection(object):
|
||||||
|
def setupUi(self, PlaylistSection):
|
||||||
|
PlaylistSection.setObjectName("PlaylistSection")
|
||||||
|
PlaylistSection.resize(1249, 499)
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(PlaylistSection)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.splitter = QtWidgets.QSplitter(parent=PlaylistSection)
|
||||||
|
self.splitter.setOrientation(QtCore.Qt.Orientation.Vertical)
|
||||||
|
self.splitter.setObjectName("splitter")
|
||||||
|
self.tabPlaylist = QtWidgets.QTabWidget(parent=self.splitter)
|
||||||
|
self.tabPlaylist.setDocumentMode(False)
|
||||||
|
self.tabPlaylist.setTabsClosable(True)
|
||||||
|
self.tabPlaylist.setMovable(True)
|
||||||
|
self.tabPlaylist.setObjectName("tabPlaylist")
|
||||||
|
self.horizontalLayout.addWidget(self.splitter)
|
||||||
|
|
||||||
|
self.retranslateUi(PlaylistSection)
|
||||||
|
self.tabPlaylist.setCurrentIndex(-1)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(PlaylistSection)
|
||||||
|
|
||||||
|
def retranslateUi(self, PlaylistSection):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
PlaylistSection.setWindowTitle(_translate("PlaylistSection", "Form"))
|
||||||
@ -1,6 +1,6 @@
|
|||||||
# Form implementation generated from reading ui file 'app/ui/main_window.ui'
|
# Form implementation generated from reading ui file 'app/ui/main_window.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt6 UI code generator 6.8.0
|
# Created by: PyQt6 UI code generator 6.8.1
|
||||||
#
|
#
|
||||||
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
|
||||||
# run again. Do not edit this file unless you know what you are doing.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
@ -15,7 +15,11 @@ class Ui_MainWindow(object):
|
|||||||
MainWindow.resize(1280, 857)
|
MainWindow.resize(1280, 857)
|
||||||
MainWindow.setMinimumSize(QtCore.QSize(1280, 0))
|
MainWindow.setMinimumSize(QtCore.QSize(1280, 0))
|
||||||
icon = QtGui.QIcon()
|
icon = QtGui.QIcon()
|
||||||
icon.addPixmap(QtGui.QPixmap(":/icons/musicmuster"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/musicmuster"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
MainWindow.setWindowIcon(icon)
|
MainWindow.setWindowIcon(icon)
|
||||||
MainWindow.setStyleSheet("")
|
MainWindow.setStyleSheet("")
|
||||||
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
|
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
|
||||||
@ -27,39 +31,62 @@ class Ui_MainWindow(object):
|
|||||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
|
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
|
||||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||||
self.previous_track_2 = QtWidgets.QLabel(parent=self.centralwidget)
|
self.previous_track_2 = QtWidgets.QLabel(parent=self.centralwidget)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
sizePolicy = QtWidgets.QSizePolicy(
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.previous_track_2.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(
|
||||||
|
self.previous_track_2.sizePolicy().hasHeightForWidth()
|
||||||
|
)
|
||||||
self.previous_track_2.setSizePolicy(sizePolicy)
|
self.previous_track_2.setSizePolicy(sizePolicy)
|
||||||
self.previous_track_2.setMaximumSize(QtCore.QSize(230, 16777215))
|
self.previous_track_2.setMaximumSize(QtCore.QSize(230, 16777215))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setFamily("Sans")
|
font.setFamily("Sans")
|
||||||
font.setPointSize(20)
|
font.setPointSize(20)
|
||||||
self.previous_track_2.setFont(font)
|
self.previous_track_2.setFont(font)
|
||||||
self.previous_track_2.setStyleSheet("background-color: #f8d7da;\n"
|
self.previous_track_2.setStyleSheet(
|
||||||
"border: 1px solid rgb(85, 87, 83);")
|
"background-color: #f8d7da;\n" "border: 1px solid rgb(85, 87, 83);"
|
||||||
self.previous_track_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
|
)
|
||||||
|
self.previous_track_2.setAlignment(
|
||||||
|
QtCore.Qt.AlignmentFlag.AlignRight
|
||||||
|
| QtCore.Qt.AlignmentFlag.AlignTrailing
|
||||||
|
| QtCore.Qt.AlignmentFlag.AlignVCenter
|
||||||
|
)
|
||||||
self.previous_track_2.setObjectName("previous_track_2")
|
self.previous_track_2.setObjectName("previous_track_2")
|
||||||
self.verticalLayout_3.addWidget(self.previous_track_2)
|
self.verticalLayout_3.addWidget(self.previous_track_2)
|
||||||
self.current_track_2 = QtWidgets.QLabel(parent=self.centralwidget)
|
self.current_track_2 = QtWidgets.QLabel(parent=self.centralwidget)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
sizePolicy = QtWidgets.QSizePolicy(
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.current_track_2.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(
|
||||||
|
self.current_track_2.sizePolicy().hasHeightForWidth()
|
||||||
|
)
|
||||||
self.current_track_2.setSizePolicy(sizePolicy)
|
self.current_track_2.setSizePolicy(sizePolicy)
|
||||||
self.current_track_2.setMaximumSize(QtCore.QSize(230, 16777215))
|
self.current_track_2.setMaximumSize(QtCore.QSize(230, 16777215))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setFamily("Sans")
|
font.setFamily("Sans")
|
||||||
font.setPointSize(20)
|
font.setPointSize(20)
|
||||||
self.current_track_2.setFont(font)
|
self.current_track_2.setFont(font)
|
||||||
self.current_track_2.setStyleSheet("background-color: #d4edda;\n"
|
self.current_track_2.setStyleSheet(
|
||||||
"border: 1px solid rgb(85, 87, 83);")
|
"background-color: #d4edda;\n" "border: 1px solid rgb(85, 87, 83);"
|
||||||
self.current_track_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
|
)
|
||||||
|
self.current_track_2.setAlignment(
|
||||||
|
QtCore.Qt.AlignmentFlag.AlignRight
|
||||||
|
| QtCore.Qt.AlignmentFlag.AlignTrailing
|
||||||
|
| QtCore.Qt.AlignmentFlag.AlignVCenter
|
||||||
|
)
|
||||||
self.current_track_2.setObjectName("current_track_2")
|
self.current_track_2.setObjectName("current_track_2")
|
||||||
self.verticalLayout_3.addWidget(self.current_track_2)
|
self.verticalLayout_3.addWidget(self.current_track_2)
|
||||||
self.next_track_2 = QtWidgets.QLabel(parent=self.centralwidget)
|
self.next_track_2 = QtWidgets.QLabel(parent=self.centralwidget)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
sizePolicy = QtWidgets.QSizePolicy(
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.next_track_2.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.next_track_2.sizePolicy().hasHeightForWidth())
|
||||||
@ -69,19 +96,29 @@ class Ui_MainWindow(object):
|
|||||||
font.setFamily("Sans")
|
font.setFamily("Sans")
|
||||||
font.setPointSize(20)
|
font.setPointSize(20)
|
||||||
self.next_track_2.setFont(font)
|
self.next_track_2.setFont(font)
|
||||||
self.next_track_2.setStyleSheet("background-color: #fff3cd;\n"
|
self.next_track_2.setStyleSheet(
|
||||||
"border: 1px solid rgb(85, 87, 83);")
|
"background-color: #fff3cd;\n" "border: 1px solid rgb(85, 87, 83);"
|
||||||
self.next_track_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTrailing|QtCore.Qt.AlignmentFlag.AlignVCenter)
|
)
|
||||||
|
self.next_track_2.setAlignment(
|
||||||
|
QtCore.Qt.AlignmentFlag.AlignRight
|
||||||
|
| QtCore.Qt.AlignmentFlag.AlignTrailing
|
||||||
|
| QtCore.Qt.AlignmentFlag.AlignVCenter
|
||||||
|
)
|
||||||
self.next_track_2.setObjectName("next_track_2")
|
self.next_track_2.setObjectName("next_track_2")
|
||||||
self.verticalLayout_3.addWidget(self.next_track_2)
|
self.verticalLayout_3.addWidget(self.next_track_2)
|
||||||
self.horizontalLayout_3.addLayout(self.verticalLayout_3)
|
self.horizontalLayout_3.addLayout(self.verticalLayout_3)
|
||||||
self.verticalLayout = QtWidgets.QVBoxLayout()
|
self.verticalLayout = QtWidgets.QVBoxLayout()
|
||||||
self.verticalLayout.setObjectName("verticalLayout")
|
self.verticalLayout.setObjectName("verticalLayout")
|
||||||
self.hdrPreviousTrack = QtWidgets.QLabel(parent=self.centralwidget)
|
self.hdrPreviousTrack = QtWidgets.QLabel(parent=self.centralwidget)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
sizePolicy = QtWidgets.QSizePolicy(
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.hdrPreviousTrack.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(
|
||||||
|
self.hdrPreviousTrack.sizePolicy().hasHeightForWidth()
|
||||||
|
)
|
||||||
self.hdrPreviousTrack.setSizePolicy(sizePolicy)
|
self.hdrPreviousTrack.setSizePolicy(sizePolicy)
|
||||||
self.hdrPreviousTrack.setMinimumSize(QtCore.QSize(0, 0))
|
self.hdrPreviousTrack.setMinimumSize(QtCore.QSize(0, 0))
|
||||||
self.hdrPreviousTrack.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
self.hdrPreviousTrack.setMaximumSize(QtCore.QSize(16777215, 16777215))
|
||||||
@ -89,32 +126,43 @@ class Ui_MainWindow(object):
|
|||||||
font.setFamily("Sans")
|
font.setFamily("Sans")
|
||||||
font.setPointSize(20)
|
font.setPointSize(20)
|
||||||
self.hdrPreviousTrack.setFont(font)
|
self.hdrPreviousTrack.setFont(font)
|
||||||
self.hdrPreviousTrack.setStyleSheet("background-color: #f8d7da;\n"
|
self.hdrPreviousTrack.setStyleSheet(
|
||||||
"border: 1px solid rgb(85, 87, 83);")
|
"background-color: #f8d7da;\n" "border: 1px solid rgb(85, 87, 83);"
|
||||||
|
)
|
||||||
self.hdrPreviousTrack.setText("")
|
self.hdrPreviousTrack.setText("")
|
||||||
self.hdrPreviousTrack.setWordWrap(False)
|
self.hdrPreviousTrack.setWordWrap(False)
|
||||||
self.hdrPreviousTrack.setObjectName("hdrPreviousTrack")
|
self.hdrPreviousTrack.setObjectName("hdrPreviousTrack")
|
||||||
self.verticalLayout.addWidget(self.hdrPreviousTrack)
|
self.verticalLayout.addWidget(self.hdrPreviousTrack)
|
||||||
self.hdrCurrentTrack = QtWidgets.QPushButton(parent=self.centralwidget)
|
self.hdrCurrentTrack = QtWidgets.QPushButton(parent=self.centralwidget)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
sizePolicy = QtWidgets.QSizePolicy(
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.hdrCurrentTrack.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(
|
||||||
|
self.hdrCurrentTrack.sizePolicy().hasHeightForWidth()
|
||||||
|
)
|
||||||
self.hdrCurrentTrack.setSizePolicy(sizePolicy)
|
self.hdrCurrentTrack.setSizePolicy(sizePolicy)
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setPointSize(20)
|
font.setPointSize(20)
|
||||||
self.hdrCurrentTrack.setFont(font)
|
self.hdrCurrentTrack.setFont(font)
|
||||||
self.hdrCurrentTrack.setStyleSheet("background-color: #d4edda;\n"
|
self.hdrCurrentTrack.setStyleSheet(
|
||||||
"border: 1px solid rgb(85, 87, 83);\n"
|
"background-color: #d4edda;\n"
|
||||||
"text-align: left;\n"
|
"border: 1px solid rgb(85, 87, 83);\n"
|
||||||
"padding-left: 8px;\n"
|
"text-align: left;\n"
|
||||||
"")
|
"padding-left: 8px;\n"
|
||||||
|
""
|
||||||
|
)
|
||||||
self.hdrCurrentTrack.setText("")
|
self.hdrCurrentTrack.setText("")
|
||||||
self.hdrCurrentTrack.setFlat(True)
|
self.hdrCurrentTrack.setFlat(True)
|
||||||
self.hdrCurrentTrack.setObjectName("hdrCurrentTrack")
|
self.hdrCurrentTrack.setObjectName("hdrCurrentTrack")
|
||||||
self.verticalLayout.addWidget(self.hdrCurrentTrack)
|
self.verticalLayout.addWidget(self.hdrCurrentTrack)
|
||||||
self.hdrNextTrack = QtWidgets.QPushButton(parent=self.centralwidget)
|
self.hdrNextTrack = QtWidgets.QPushButton(parent=self.centralwidget)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
sizePolicy = QtWidgets.QSizePolicy(
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.hdrNextTrack.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.hdrNextTrack.sizePolicy().hasHeightForWidth())
|
||||||
@ -122,10 +170,12 @@ class Ui_MainWindow(object):
|
|||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setPointSize(20)
|
font.setPointSize(20)
|
||||||
self.hdrNextTrack.setFont(font)
|
self.hdrNextTrack.setFont(font)
|
||||||
self.hdrNextTrack.setStyleSheet("background-color: #fff3cd;\n"
|
self.hdrNextTrack.setStyleSheet(
|
||||||
"border: 1px solid rgb(85, 87, 83);\n"
|
"background-color: #fff3cd;\n"
|
||||||
"text-align: left;\n"
|
"border: 1px solid rgb(85, 87, 83);\n"
|
||||||
"padding-left: 8px;")
|
"text-align: left;\n"
|
||||||
|
"padding-left: 8px;"
|
||||||
|
)
|
||||||
self.hdrNextTrack.setText("")
|
self.hdrNextTrack.setText("")
|
||||||
self.hdrNextTrack.setFlat(True)
|
self.hdrNextTrack.setFlat(True)
|
||||||
self.hdrNextTrack.setObjectName("hdrNextTrack")
|
self.hdrNextTrack.setObjectName("hdrNextTrack")
|
||||||
@ -172,7 +222,12 @@ class Ui_MainWindow(object):
|
|||||||
self.cartsWidget.setObjectName("cartsWidget")
|
self.cartsWidget.setObjectName("cartsWidget")
|
||||||
self.horizontalLayout_Carts = QtWidgets.QHBoxLayout(self.cartsWidget)
|
self.horizontalLayout_Carts = QtWidgets.QHBoxLayout(self.cartsWidget)
|
||||||
self.horizontalLayout_Carts.setObjectName("horizontalLayout_Carts")
|
self.horizontalLayout_Carts.setObjectName("horizontalLayout_Carts")
|
||||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
spacerItem = QtWidgets.QSpacerItem(
|
||||||
|
40,
|
||||||
|
20,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Expanding,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Minimum,
|
||||||
|
)
|
||||||
self.horizontalLayout_Carts.addItem(spacerItem)
|
self.horizontalLayout_Carts.addItem(spacerItem)
|
||||||
self.gridLayout_4.addWidget(self.cartsWidget, 2, 0, 1, 1)
|
self.gridLayout_4.addWidget(self.cartsWidget, 2, 0, 1, 1)
|
||||||
self.frame_6 = QtWidgets.QFrame(parent=self.centralwidget)
|
self.frame_6 = QtWidgets.QFrame(parent=self.centralwidget)
|
||||||
@ -217,7 +272,11 @@ class Ui_MainWindow(object):
|
|||||||
self.btnPreview = QtWidgets.QPushButton(parent=self.FadeStopInfoFrame)
|
self.btnPreview = QtWidgets.QPushButton(parent=self.FadeStopInfoFrame)
|
||||||
self.btnPreview.setMinimumSize(QtCore.QSize(132, 41))
|
self.btnPreview.setMinimumSize(QtCore.QSize(132, 41))
|
||||||
icon1 = QtGui.QIcon()
|
icon1 = QtGui.QIcon()
|
||||||
icon1.addPixmap(QtGui.QPixmap(":/icons/headphones"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon1.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/headphones"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.btnPreview.setIcon(icon1)
|
self.btnPreview.setIcon(icon1)
|
||||||
self.btnPreview.setIconSize(QtCore.QSize(30, 30))
|
self.btnPreview.setIconSize(QtCore.QSize(30, 30))
|
||||||
self.btnPreview.setCheckable(True)
|
self.btnPreview.setCheckable(True)
|
||||||
@ -239,8 +298,16 @@ class Ui_MainWindow(object):
|
|||||||
self.btnPreviewArm.setMaximumSize(QtCore.QSize(44, 23))
|
self.btnPreviewArm.setMaximumSize(QtCore.QSize(44, 23))
|
||||||
self.btnPreviewArm.setText("")
|
self.btnPreviewArm.setText("")
|
||||||
icon2 = QtGui.QIcon()
|
icon2 = QtGui.QIcon()
|
||||||
icon2.addPixmap(QtGui.QPixmap(":/icons/record-button.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon2.addPixmap(
|
||||||
icon2.addPixmap(QtGui.QPixmap(":/icons/record-red-button.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On)
|
QtGui.QPixmap(":/icons/record-button.png"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
|
icon2.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/record-red-button.png"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.On,
|
||||||
|
)
|
||||||
self.btnPreviewArm.setIcon(icon2)
|
self.btnPreviewArm.setIcon(icon2)
|
||||||
self.btnPreviewArm.setCheckable(True)
|
self.btnPreviewArm.setCheckable(True)
|
||||||
self.btnPreviewArm.setObjectName("btnPreviewArm")
|
self.btnPreviewArm.setObjectName("btnPreviewArm")
|
||||||
@ -261,8 +328,16 @@ class Ui_MainWindow(object):
|
|||||||
self.btnPreviewMark.setMaximumSize(QtCore.QSize(44, 23))
|
self.btnPreviewMark.setMaximumSize(QtCore.QSize(44, 23))
|
||||||
self.btnPreviewMark.setText("")
|
self.btnPreviewMark.setText("")
|
||||||
icon3 = QtGui.QIcon()
|
icon3 = QtGui.QIcon()
|
||||||
icon3.addPixmap(QtGui.QPixmap(":/icons/star.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On)
|
icon3.addPixmap(
|
||||||
icon3.addPixmap(QtGui.QPixmap(":/icons/star_empty.png"), QtGui.QIcon.Mode.Disabled, QtGui.QIcon.State.Off)
|
QtGui.QPixmap(":/icons/star.png"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.On,
|
||||||
|
)
|
||||||
|
icon3.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/star_empty.png"),
|
||||||
|
QtGui.QIcon.Mode.Disabled,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.btnPreviewMark.setIcon(icon3)
|
self.btnPreviewMark.setIcon(icon3)
|
||||||
self.btnPreviewMark.setObjectName("btnPreviewMark")
|
self.btnPreviewMark.setObjectName("btnPreviewMark")
|
||||||
self.btnPreviewFwd = QtWidgets.QPushButton(parent=self.groupBoxIntroControls)
|
self.btnPreviewFwd = QtWidgets.QPushButton(parent=self.groupBoxIntroControls)
|
||||||
@ -363,10 +438,15 @@ class Ui_MainWindow(object):
|
|||||||
self.verticalLayout_7.addWidget(self.label_silent_timer)
|
self.verticalLayout_7.addWidget(self.label_silent_timer)
|
||||||
self.horizontalLayout.addWidget(self.frame_silent)
|
self.horizontalLayout.addWidget(self.frame_silent)
|
||||||
self.widgetFadeVolume = PlotWidget(parent=self.InfoFooterFrame)
|
self.widgetFadeVolume = PlotWidget(parent=self.InfoFooterFrame)
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
|
sizePolicy = QtWidgets.QSizePolicy(
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
QtWidgets.QSizePolicy.Policy.Preferred,
|
||||||
|
)
|
||||||
sizePolicy.setHorizontalStretch(1)
|
sizePolicy.setHorizontalStretch(1)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.widgetFadeVolume.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(
|
||||||
|
self.widgetFadeVolume.sizePolicy().hasHeightForWidth()
|
||||||
|
)
|
||||||
self.widgetFadeVolume.setSizePolicy(sizePolicy)
|
self.widgetFadeVolume.setSizePolicy(sizePolicy)
|
||||||
self.widgetFadeVolume.setMinimumSize(QtCore.QSize(0, 0))
|
self.widgetFadeVolume.setMinimumSize(QtCore.QSize(0, 0))
|
||||||
self.widgetFadeVolume.setObjectName("widgetFadeVolume")
|
self.widgetFadeVolume.setObjectName("widgetFadeVolume")
|
||||||
@ -383,7 +463,11 @@ class Ui_MainWindow(object):
|
|||||||
self.btnFade.setMinimumSize(QtCore.QSize(132, 32))
|
self.btnFade.setMinimumSize(QtCore.QSize(132, 32))
|
||||||
self.btnFade.setMaximumSize(QtCore.QSize(164, 16777215))
|
self.btnFade.setMaximumSize(QtCore.QSize(164, 16777215))
|
||||||
icon4 = QtGui.QIcon()
|
icon4 = QtGui.QIcon()
|
||||||
icon4.addPixmap(QtGui.QPixmap(":/icons/fade"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon4.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/fade"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.btnFade.setIcon(icon4)
|
self.btnFade.setIcon(icon4)
|
||||||
self.btnFade.setIconSize(QtCore.QSize(30, 30))
|
self.btnFade.setIconSize(QtCore.QSize(30, 30))
|
||||||
self.btnFade.setObjectName("btnFade")
|
self.btnFade.setObjectName("btnFade")
|
||||||
@ -391,7 +475,11 @@ class Ui_MainWindow(object):
|
|||||||
self.btnStop = QtWidgets.QPushButton(parent=self.frame)
|
self.btnStop = QtWidgets.QPushButton(parent=self.frame)
|
||||||
self.btnStop.setMinimumSize(QtCore.QSize(0, 36))
|
self.btnStop.setMinimumSize(QtCore.QSize(0, 36))
|
||||||
icon5 = QtGui.QIcon()
|
icon5 = QtGui.QIcon()
|
||||||
icon5.addPixmap(QtGui.QPixmap(":/icons/stopsign"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon5.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/stopsign"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.btnStop.setIcon(icon5)
|
self.btnStop.setIcon(icon5)
|
||||||
self.btnStop.setObjectName("btnStop")
|
self.btnStop.setObjectName("btnStop")
|
||||||
self.verticalLayout_5.addWidget(self.btnStop)
|
self.verticalLayout_5.addWidget(self.btnStop)
|
||||||
@ -417,39 +505,71 @@ class Ui_MainWindow(object):
|
|||||||
MainWindow.setStatusBar(self.statusbar)
|
MainWindow.setStatusBar(self.statusbar)
|
||||||
self.actionPlay_next = QtGui.QAction(parent=MainWindow)
|
self.actionPlay_next = QtGui.QAction(parent=MainWindow)
|
||||||
icon6 = QtGui.QIcon()
|
icon6 = QtGui.QIcon()
|
||||||
icon6.addPixmap(QtGui.QPixmap("app/ui/../../../../../../.designer/backup/icon-play.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon6.addPixmap(
|
||||||
|
QtGui.QPixmap("app/ui/../../../../../../.designer/backup/icon-play.png"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.actionPlay_next.setIcon(icon6)
|
self.actionPlay_next.setIcon(icon6)
|
||||||
self.actionPlay_next.setObjectName("actionPlay_next")
|
self.actionPlay_next.setObjectName("actionPlay_next")
|
||||||
self.actionSkipToNext = QtGui.QAction(parent=MainWindow)
|
self.actionSkipToNext = QtGui.QAction(parent=MainWindow)
|
||||||
icon7 = QtGui.QIcon()
|
icon7 = QtGui.QIcon()
|
||||||
icon7.addPixmap(QtGui.QPixmap(":/icons/next"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon7.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/next"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.actionSkipToNext.setIcon(icon7)
|
self.actionSkipToNext.setIcon(icon7)
|
||||||
self.actionSkipToNext.setObjectName("actionSkipToNext")
|
self.actionSkipToNext.setObjectName("actionSkipToNext")
|
||||||
self.actionInsertTrack = QtGui.QAction(parent=MainWindow)
|
self.actionInsertTrack = QtGui.QAction(parent=MainWindow)
|
||||||
icon8 = QtGui.QIcon()
|
icon8 = QtGui.QIcon()
|
||||||
icon8.addPixmap(QtGui.QPixmap("app/ui/../../../../../../.designer/backup/icon_search_database.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon8.addPixmap(
|
||||||
|
QtGui.QPixmap(
|
||||||
|
"app/ui/../../../../../../.designer/backup/icon_search_database.png"
|
||||||
|
),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.actionInsertTrack.setIcon(icon8)
|
self.actionInsertTrack.setIcon(icon8)
|
||||||
self.actionInsertTrack.setObjectName("actionInsertTrack")
|
self.actionInsertTrack.setObjectName("actionInsertTrack")
|
||||||
self.actionAdd_file = QtGui.QAction(parent=MainWindow)
|
self.actionAdd_file = QtGui.QAction(parent=MainWindow)
|
||||||
icon9 = QtGui.QIcon()
|
icon9 = QtGui.QIcon()
|
||||||
icon9.addPixmap(QtGui.QPixmap("app/ui/../../../../../../.designer/backup/icon_open_file.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon9.addPixmap(
|
||||||
|
QtGui.QPixmap(
|
||||||
|
"app/ui/../../../../../../.designer/backup/icon_open_file.png"
|
||||||
|
),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.actionAdd_file.setIcon(icon9)
|
self.actionAdd_file.setIcon(icon9)
|
||||||
self.actionAdd_file.setObjectName("actionAdd_file")
|
self.actionAdd_file.setObjectName("actionAdd_file")
|
||||||
self.actionFade = QtGui.QAction(parent=MainWindow)
|
self.actionFade = QtGui.QAction(parent=MainWindow)
|
||||||
icon10 = QtGui.QIcon()
|
icon10 = QtGui.QIcon()
|
||||||
icon10.addPixmap(QtGui.QPixmap("app/ui/../../../../../../.designer/backup/icon-fade.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon10.addPixmap(
|
||||||
|
QtGui.QPixmap("app/ui/../../../../../../.designer/backup/icon-fade.png"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.actionFade.setIcon(icon10)
|
self.actionFade.setIcon(icon10)
|
||||||
self.actionFade.setObjectName("actionFade")
|
self.actionFade.setObjectName("actionFade")
|
||||||
self.actionStop = QtGui.QAction(parent=MainWindow)
|
self.actionStop = QtGui.QAction(parent=MainWindow)
|
||||||
icon11 = QtGui.QIcon()
|
icon11 = QtGui.QIcon()
|
||||||
icon11.addPixmap(QtGui.QPixmap(":/icons/stop"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon11.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/stop"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.actionStop.setIcon(icon11)
|
self.actionStop.setIcon(icon11)
|
||||||
self.actionStop.setObjectName("actionStop")
|
self.actionStop.setObjectName("actionStop")
|
||||||
self.action_Clear_selection = QtGui.QAction(parent=MainWindow)
|
self.action_Clear_selection = QtGui.QAction(parent=MainWindow)
|
||||||
self.action_Clear_selection.setObjectName("action_Clear_selection")
|
self.action_Clear_selection.setObjectName("action_Clear_selection")
|
||||||
self.action_Resume_previous = QtGui.QAction(parent=MainWindow)
|
self.action_Resume_previous = QtGui.QAction(parent=MainWindow)
|
||||||
icon12 = QtGui.QIcon()
|
icon12 = QtGui.QIcon()
|
||||||
icon12.addPixmap(QtGui.QPixmap(":/icons/previous"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
icon12.addPixmap(
|
||||||
|
QtGui.QPixmap(":/icons/previous"),
|
||||||
|
QtGui.QIcon.Mode.Normal,
|
||||||
|
QtGui.QIcon.State.Off,
|
||||||
|
)
|
||||||
self.action_Resume_previous.setIcon(icon12)
|
self.action_Resume_previous.setIcon(icon12)
|
||||||
self.action_Resume_previous.setObjectName("action_Resume_previous")
|
self.action_Resume_previous.setObjectName("action_Resume_previous")
|
||||||
self.actionE_xit = QtGui.QAction(parent=MainWindow)
|
self.actionE_xit = QtGui.QAction(parent=MainWindow)
|
||||||
@ -496,7 +616,9 @@ class Ui_MainWindow(object):
|
|||||||
self.actionImport = QtGui.QAction(parent=MainWindow)
|
self.actionImport = QtGui.QAction(parent=MainWindow)
|
||||||
self.actionImport.setObjectName("actionImport")
|
self.actionImport.setObjectName("actionImport")
|
||||||
self.actionDownload_CSV_of_played_tracks = QtGui.QAction(parent=MainWindow)
|
self.actionDownload_CSV_of_played_tracks = QtGui.QAction(parent=MainWindow)
|
||||||
self.actionDownload_CSV_of_played_tracks.setObjectName("actionDownload_CSV_of_played_tracks")
|
self.actionDownload_CSV_of_played_tracks.setObjectName(
|
||||||
|
"actionDownload_CSV_of_played_tracks"
|
||||||
|
)
|
||||||
self.actionSearch = QtGui.QAction(parent=MainWindow)
|
self.actionSearch = QtGui.QAction(parent=MainWindow)
|
||||||
self.actionSearch.setObjectName("actionSearch")
|
self.actionSearch.setObjectName("actionSearch")
|
||||||
self.actionInsertSectionHeader = QtGui.QAction(parent=MainWindow)
|
self.actionInsertSectionHeader = QtGui.QAction(parent=MainWindow)
|
||||||
@ -524,13 +646,21 @@ class Ui_MainWindow(object):
|
|||||||
self.actionResume = QtGui.QAction(parent=MainWindow)
|
self.actionResume = QtGui.QAction(parent=MainWindow)
|
||||||
self.actionResume.setObjectName("actionResume")
|
self.actionResume.setObjectName("actionResume")
|
||||||
self.actionSearch_title_in_Wikipedia = QtGui.QAction(parent=MainWindow)
|
self.actionSearch_title_in_Wikipedia = QtGui.QAction(parent=MainWindow)
|
||||||
self.actionSearch_title_in_Wikipedia.setObjectName("actionSearch_title_in_Wikipedia")
|
self.actionSearch_title_in_Wikipedia.setObjectName(
|
||||||
|
"actionSearch_title_in_Wikipedia"
|
||||||
|
)
|
||||||
self.actionSearch_title_in_Songfacts = QtGui.QAction(parent=MainWindow)
|
self.actionSearch_title_in_Songfacts = QtGui.QAction(parent=MainWindow)
|
||||||
self.actionSearch_title_in_Songfacts.setObjectName("actionSearch_title_in_Songfacts")
|
self.actionSearch_title_in_Songfacts.setObjectName(
|
||||||
|
"actionSearch_title_in_Songfacts"
|
||||||
|
)
|
||||||
self.actionSelect_duplicate_rows = QtGui.QAction(parent=MainWindow)
|
self.actionSelect_duplicate_rows = QtGui.QAction(parent=MainWindow)
|
||||||
self.actionSelect_duplicate_rows.setObjectName("actionSelect_duplicate_rows")
|
self.actionSelect_duplicate_rows.setObjectName("actionSelect_duplicate_rows")
|
||||||
self.actionImport_files = QtGui.QAction(parent=MainWindow)
|
self.actionImport_files = QtGui.QAction(parent=MainWindow)
|
||||||
self.actionImport_files.setObjectName("actionImport_files")
|
self.actionImport_files.setObjectName("actionImport_files")
|
||||||
|
self.actionOpenQuerylist = QtGui.QAction(parent=MainWindow)
|
||||||
|
self.actionOpenQuerylist.setObjectName("actionOpenQuerylist")
|
||||||
|
self.actionManage_querylists = QtGui.QAction(parent=MainWindow)
|
||||||
|
self.actionManage_querylists.setObjectName("actionManage_querylists")
|
||||||
self.menuFile.addSeparator()
|
self.menuFile.addSeparator()
|
||||||
self.menuFile.addAction(self.actionInsertTrack)
|
self.menuFile.addAction(self.actionInsertTrack)
|
||||||
self.menuFile.addAction(self.actionRemove)
|
self.menuFile.addAction(self.actionRemove)
|
||||||
@ -554,6 +684,9 @@ class Ui_MainWindow(object):
|
|||||||
self.menuPlaylist.addAction(self.actionRenamePlaylist)
|
self.menuPlaylist.addAction(self.actionRenamePlaylist)
|
||||||
self.menuPlaylist.addAction(self.actionDeletePlaylist)
|
self.menuPlaylist.addAction(self.actionDeletePlaylist)
|
||||||
self.menuPlaylist.addSeparator()
|
self.menuPlaylist.addSeparator()
|
||||||
|
self.menuPlaylist.addAction(self.actionOpenQuerylist)
|
||||||
|
self.menuPlaylist.addAction(self.actionManage_querylists)
|
||||||
|
self.menuPlaylist.addSeparator()
|
||||||
self.menuPlaylist.addAction(self.actionSave_as_template)
|
self.menuPlaylist.addAction(self.actionSave_as_template)
|
||||||
self.menuPlaylist.addAction(self.actionManage_templates)
|
self.menuPlaylist.addAction(self.actionManage_templates)
|
||||||
self.menuPlaylist.addSeparator()
|
self.menuPlaylist.addSeparator()
|
||||||
@ -580,7 +713,7 @@ class Ui_MainWindow(object):
|
|||||||
self.retranslateUi(MainWindow)
|
self.retranslateUi(MainWindow)
|
||||||
self.tabPlaylist.setCurrentIndex(-1)
|
self.tabPlaylist.setCurrentIndex(-1)
|
||||||
self.tabInfolist.setCurrentIndex(-1)
|
self.tabInfolist.setCurrentIndex(-1)
|
||||||
self.actionE_xit.triggered.connect(MainWindow.close) # type: ignore
|
self.actionE_xit.triggered.connect(MainWindow.close) # type: ignore
|
||||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||||
|
|
||||||
def retranslateUi(self, MainWindow):
|
def retranslateUi(self, MainWindow):
|
||||||
@ -622,38 +755,58 @@ class Ui_MainWindow(object):
|
|||||||
self.actionFade.setShortcut(_translate("MainWindow", "Ctrl+Z"))
|
self.actionFade.setShortcut(_translate("MainWindow", "Ctrl+Z"))
|
||||||
self.actionStop.setText(_translate("MainWindow", "S&top"))
|
self.actionStop.setText(_translate("MainWindow", "S&top"))
|
||||||
self.actionStop.setShortcut(_translate("MainWindow", "Ctrl+Alt+S"))
|
self.actionStop.setShortcut(_translate("MainWindow", "Ctrl+Alt+S"))
|
||||||
self.action_Clear_selection.setText(_translate("MainWindow", "Clear &selection"))
|
self.action_Clear_selection.setText(
|
||||||
|
_translate("MainWindow", "Clear &selection")
|
||||||
|
)
|
||||||
self.action_Clear_selection.setShortcut(_translate("MainWindow", "Esc"))
|
self.action_Clear_selection.setShortcut(_translate("MainWindow", "Esc"))
|
||||||
self.action_Resume_previous.setText(_translate("MainWindow", "&Resume previous"))
|
self.action_Resume_previous.setText(
|
||||||
|
_translate("MainWindow", "&Resume previous")
|
||||||
|
)
|
||||||
self.actionE_xit.setText(_translate("MainWindow", "E&xit"))
|
self.actionE_xit.setText(_translate("MainWindow", "E&xit"))
|
||||||
self.actionTest.setText(_translate("MainWindow", "&Test"))
|
self.actionTest.setText(_translate("MainWindow", "&Test"))
|
||||||
self.actionOpenPlaylist.setText(_translate("MainWindow", "O&pen..."))
|
self.actionOpenPlaylist.setText(_translate("MainWindow", "Open &playlist..."))
|
||||||
self.actionNewPlaylist.setText(_translate("MainWindow", "&New..."))
|
self.actionNewPlaylist.setText(_translate("MainWindow", "&New..."))
|
||||||
self.actionTestFunction.setText(_translate("MainWindow", "&Test function"))
|
self.actionTestFunction.setText(_translate("MainWindow", "&Test function"))
|
||||||
self.actionSkipToFade.setText(_translate("MainWindow", "&Skip to start of fade"))
|
self.actionSkipToFade.setText(
|
||||||
|
_translate("MainWindow", "&Skip to start of fade")
|
||||||
|
)
|
||||||
self.actionSkipToEnd.setText(_translate("MainWindow", "Skip to &end of track"))
|
self.actionSkipToEnd.setText(_translate("MainWindow", "Skip to &end of track"))
|
||||||
self.actionClosePlaylist.setText(_translate("MainWindow", "&Close"))
|
self.actionClosePlaylist.setText(_translate("MainWindow", "&Close"))
|
||||||
self.actionRenamePlaylist.setText(_translate("MainWindow", "&Rename..."))
|
self.actionRenamePlaylist.setText(_translate("MainWindow", "&Rename..."))
|
||||||
self.actionDeletePlaylist.setText(_translate("MainWindow", "Dele&te..."))
|
self.actionDeletePlaylist.setText(_translate("MainWindow", "Dele&te..."))
|
||||||
self.actionMoveSelected.setText(_translate("MainWindow", "Mo&ve selected tracks to..."))
|
self.actionMoveSelected.setText(
|
||||||
|
_translate("MainWindow", "Mo&ve selected tracks to...")
|
||||||
|
)
|
||||||
self.actionExport_playlist.setText(_translate("MainWindow", "E&xport..."))
|
self.actionExport_playlist.setText(_translate("MainWindow", "E&xport..."))
|
||||||
self.actionSetNext.setText(_translate("MainWindow", "Set &next"))
|
self.actionSetNext.setText(_translate("MainWindow", "Set &next"))
|
||||||
self.actionSetNext.setShortcut(_translate("MainWindow", "Ctrl+N"))
|
self.actionSetNext.setShortcut(_translate("MainWindow", "Ctrl+N"))
|
||||||
self.actionSelect_next_track.setText(_translate("MainWindow", "Select next track"))
|
self.actionSelect_next_track.setText(
|
||||||
|
_translate("MainWindow", "Select next track")
|
||||||
|
)
|
||||||
self.actionSelect_next_track.setShortcut(_translate("MainWindow", "J"))
|
self.actionSelect_next_track.setShortcut(_translate("MainWindow", "J"))
|
||||||
self.actionSelect_previous_track.setText(_translate("MainWindow", "Select previous track"))
|
self.actionSelect_previous_track.setText(
|
||||||
|
_translate("MainWindow", "Select previous track")
|
||||||
|
)
|
||||||
self.actionSelect_previous_track.setShortcut(_translate("MainWindow", "K"))
|
self.actionSelect_previous_track.setShortcut(_translate("MainWindow", "K"))
|
||||||
self.actionSelect_played_tracks.setText(_translate("MainWindow", "Select played tracks"))
|
self.actionSelect_played_tracks.setText(
|
||||||
self.actionMoveUnplayed.setText(_translate("MainWindow", "Move &unplayed tracks to..."))
|
_translate("MainWindow", "Select played tracks")
|
||||||
|
)
|
||||||
|
self.actionMoveUnplayed.setText(
|
||||||
|
_translate("MainWindow", "Move &unplayed tracks to...")
|
||||||
|
)
|
||||||
self.actionAdd_note.setText(_translate("MainWindow", "Add note..."))
|
self.actionAdd_note.setText(_translate("MainWindow", "Add note..."))
|
||||||
self.actionAdd_note.setShortcut(_translate("MainWindow", "Ctrl+T"))
|
self.actionAdd_note.setShortcut(_translate("MainWindow", "Ctrl+T"))
|
||||||
self.actionEnable_controls.setText(_translate("MainWindow", "Enable controls"))
|
self.actionEnable_controls.setText(_translate("MainWindow", "Enable controls"))
|
||||||
self.actionImport.setText(_translate("MainWindow", "Import track..."))
|
self.actionImport.setText(_translate("MainWindow", "Import track..."))
|
||||||
self.actionImport.setShortcut(_translate("MainWindow", "Ctrl+Shift+I"))
|
self.actionImport.setShortcut(_translate("MainWindow", "Ctrl+Shift+I"))
|
||||||
self.actionDownload_CSV_of_played_tracks.setText(_translate("MainWindow", "Download CSV of played tracks..."))
|
self.actionDownload_CSV_of_played_tracks.setText(
|
||||||
|
_translate("MainWindow", "Download CSV of played tracks...")
|
||||||
|
)
|
||||||
self.actionSearch.setText(_translate("MainWindow", "Search..."))
|
self.actionSearch.setText(_translate("MainWindow", "Search..."))
|
||||||
self.actionSearch.setShortcut(_translate("MainWindow", "/"))
|
self.actionSearch.setShortcut(_translate("MainWindow", "/"))
|
||||||
self.actionInsertSectionHeader.setText(_translate("MainWindow", "Insert §ion header..."))
|
self.actionInsertSectionHeader.setText(
|
||||||
|
_translate("MainWindow", "Insert §ion header...")
|
||||||
|
)
|
||||||
self.actionInsertSectionHeader.setShortcut(_translate("MainWindow", "Ctrl+H"))
|
self.actionInsertSectionHeader.setShortcut(_translate("MainWindow", "Ctrl+H"))
|
||||||
self.actionRemove.setText(_translate("MainWindow", "&Remove track"))
|
self.actionRemove.setText(_translate("MainWindow", "&Remove track"))
|
||||||
self.actionFind_next.setText(_translate("MainWindow", "Find next"))
|
self.actionFind_next.setText(_translate("MainWindow", "Find next"))
|
||||||
@ -661,8 +814,12 @@ class Ui_MainWindow(object):
|
|||||||
self.actionFind_previous.setText(_translate("MainWindow", "Find previous"))
|
self.actionFind_previous.setText(_translate("MainWindow", "Find previous"))
|
||||||
self.actionFind_previous.setShortcut(_translate("MainWindow", "P"))
|
self.actionFind_previous.setShortcut(_translate("MainWindow", "P"))
|
||||||
self.action_About.setText(_translate("MainWindow", "&About"))
|
self.action_About.setText(_translate("MainWindow", "&About"))
|
||||||
self.actionSave_as_template.setText(_translate("MainWindow", "Save as template..."))
|
self.actionSave_as_template.setText(
|
||||||
self.actionManage_templates.setText(_translate("MainWindow", "Manage templates..."))
|
_translate("MainWindow", "Save as template...")
|
||||||
|
)
|
||||||
|
self.actionManage_templates.setText(
|
||||||
|
_translate("MainWindow", "Manage templates...")
|
||||||
|
)
|
||||||
self.actionDebug.setText(_translate("MainWindow", "Debug"))
|
self.actionDebug.setText(_translate("MainWindow", "Debug"))
|
||||||
self.actionAdd_cart.setText(_translate("MainWindow", "Edit cart &1..."))
|
self.actionAdd_cart.setText(_translate("MainWindow", "Edit cart &1..."))
|
||||||
self.actionMark_for_moving.setText(_translate("MainWindow", "Mark for moving"))
|
self.actionMark_for_moving.setText(_translate("MainWindow", "Mark for moving"))
|
||||||
@ -671,11 +828,23 @@ class Ui_MainWindow(object):
|
|||||||
self.actionPaste.setShortcut(_translate("MainWindow", "Ctrl+V"))
|
self.actionPaste.setShortcut(_translate("MainWindow", "Ctrl+V"))
|
||||||
self.actionResume.setText(_translate("MainWindow", "Resume"))
|
self.actionResume.setText(_translate("MainWindow", "Resume"))
|
||||||
self.actionResume.setShortcut(_translate("MainWindow", "Ctrl+R"))
|
self.actionResume.setShortcut(_translate("MainWindow", "Ctrl+R"))
|
||||||
self.actionSearch_title_in_Wikipedia.setText(_translate("MainWindow", "Search title in Wikipedia"))
|
self.actionSearch_title_in_Wikipedia.setText(
|
||||||
self.actionSearch_title_in_Wikipedia.setShortcut(_translate("MainWindow", "Ctrl+W"))
|
_translate("MainWindow", "Search title in Wikipedia")
|
||||||
self.actionSearch_title_in_Songfacts.setText(_translate("MainWindow", "Search title in Songfacts"))
|
)
|
||||||
self.actionSearch_title_in_Songfacts.setShortcut(_translate("MainWindow", "Ctrl+S"))
|
self.actionSearch_title_in_Wikipedia.setShortcut(
|
||||||
self.actionSelect_duplicate_rows.setText(_translate("MainWindow", "Select duplicate rows..."))
|
_translate("MainWindow", "Ctrl+W")
|
||||||
|
)
|
||||||
|
self.actionSearch_title_in_Songfacts.setText(
|
||||||
|
_translate("MainWindow", "Search title in Songfacts")
|
||||||
|
)
|
||||||
|
self.actionSearch_title_in_Songfacts.setShortcut(
|
||||||
|
_translate("MainWindow", "Ctrl+S")
|
||||||
|
)
|
||||||
|
self.actionSelect_duplicate_rows.setText(
|
||||||
|
_translate("MainWindow", "Select duplicate rows...")
|
||||||
|
)
|
||||||
self.actionImport_files.setText(_translate("MainWindow", "Import files..."))
|
self.actionImport_files.setText(_translate("MainWindow", "Import files..."))
|
||||||
|
|
||||||
|
|
||||||
from infotabs import InfoTabs
|
from infotabs import InfoTabs
|
||||||
from pyqtgraph import PlotWidget # type: ignore
|
from pyqtgraph import PlotWidget
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
from importlib import import_module
|
|
||||||
from alembic import context
|
|
||||||
from alchemical.alembic.env import run_migrations
|
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
|
||||||
# access to the values within the .ini file in use.
|
|
||||||
config = context.config
|
|
||||||
|
|
||||||
# import the application's Alchemical instance
|
|
||||||
try:
|
|
||||||
import_mod, db_name = config.get_main_option('alchemical_db', '').split(
|
|
||||||
':')
|
|
||||||
db = getattr(import_module(import_mod), db_name)
|
|
||||||
except (ModuleNotFoundError, AttributeError):
|
|
||||||
raise ValueError(
|
|
||||||
'Could not import the Alchemical database instance. '
|
|
||||||
'Ensure that the alchemical_db setting in alembic.ini is correct.'
|
|
||||||
)
|
|
||||||
|
|
||||||
# run the migration engine
|
|
||||||
# The dictionary provided as second argument includes options to pass to the
|
|
||||||
# Alembic context. For details on what other options are available, see
|
|
||||||
# https://alembic.sqlalchemy.org/en/latest/autogenerate.html
|
|
||||||
run_migrations(db, {
|
|
||||||
'render_as_batch': True,
|
|
||||||
'compare_type': True,
|
|
||||||
})
|
|
||||||
1
migrations/env.py
Symbolic link
1
migrations/env.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
env.py.DEBUG
|
||||||
28
migrations/env.py.DEBUG
Normal file
28
migrations/env.py.DEBUG
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from importlib import import_module
|
||||||
|
from alembic import context
|
||||||
|
from alchemical.alembic.env import run_migrations
|
||||||
|
|
||||||
|
# Load Alembic configuration
|
||||||
|
config = context.config
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Import the Alchemical database instance as specified in alembic.ini
|
||||||
|
import_mod, db_name = config.get_main_option('alchemical_db', '').split(':')
|
||||||
|
db = getattr(import_module(import_mod), db_name)
|
||||||
|
print(f"Successfully loaded Alchemical database instance: {db}")
|
||||||
|
|
||||||
|
# Use the metadata associated with the Alchemical instance
|
||||||
|
metadata = db.Model.metadata
|
||||||
|
print(f"Metadata tables detected: {metadata.tables.keys()}") # Debug output
|
||||||
|
except (ModuleNotFoundError, AttributeError) as e:
|
||||||
|
raise ValueError(
|
||||||
|
'Could not import the Alchemical database instance or access metadata. '
|
||||||
|
'Ensure that the alchemical_db setting in alembic.ini is correct and '
|
||||||
|
'that the Alchemical instance is correctly configured.'
|
||||||
|
) from e
|
||||||
|
|
||||||
|
# Run migrations with metadata
|
||||||
|
run_migrations(db, {
|
||||||
|
'render_as_batch': True,
|
||||||
|
'compare_type': True,
|
||||||
|
})
|
||||||
27
migrations/env.py.NODEBUG
Normal file
27
migrations/env.py.NODEBUG
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from importlib import import_module
|
||||||
|
from alembic import context
|
||||||
|
from alchemical.alembic.env import run_migrations
|
||||||
|
|
||||||
|
# this is the Alembic Config object, which provides
|
||||||
|
# access to the values within the .ini file in use.
|
||||||
|
config = context.config
|
||||||
|
|
||||||
|
# import the application's Alchemical instance
|
||||||
|
try:
|
||||||
|
import_mod, db_name = config.get_main_option('alchemical_db', '').split(
|
||||||
|
':')
|
||||||
|
db = getattr(import_module(import_mod), db_name)
|
||||||
|
except (ModuleNotFoundError, AttributeError):
|
||||||
|
raise ValueError(
|
||||||
|
'Could not import the Alchemical database instance. '
|
||||||
|
'Ensure that the alchemical_db setting in alembic.ini is correct.'
|
||||||
|
)
|
||||||
|
|
||||||
|
# run the migration engine
|
||||||
|
# The dictionary provided as second argument includes options to pass to the
|
||||||
|
# Alembic context. For details on what other options are available, see
|
||||||
|
# https://alembic.sqlalchemy.org/en/latest/autogenerate.html
|
||||||
|
run_migrations(db, {
|
||||||
|
'render_as_batch': True,
|
||||||
|
'compare_type': True,
|
||||||
|
})
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
"""Add data for query playlists
|
||||||
|
|
||||||
|
Revision ID: 014f2d4c88a5
|
||||||
|
Revises: 33c04e3c12c8
|
||||||
|
Create Date: 2024-12-30 14:23:36.924478
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '014f2d4c88a5'
|
||||||
|
down_revision = '33c04e3c12c8'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(engine_name: str) -> None:
|
||||||
|
globals()["upgrade_%s" % engine_name]()
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(engine_name: str) -> None:
|
||||||
|
globals()["downgrade_%s" % engine_name]()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade_() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('queries',
|
||||||
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||||
|
sa.Column('query', sa.String(length=2048), nullable=False),
|
||||||
|
sa.Column('playlist_id', sa.Integer(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['playlist_id'], ['playlists.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
with op.batch_alter_table('queries', schema=None) as batch_op:
|
||||||
|
batch_op.create_index(batch_op.f('ix_queries_playlist_id'), ['playlist_id'], unique=False)
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade_() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('queries', schema=None) as batch_op:
|
||||||
|
batch_op.drop_index(batch_op.f('ix_queries_playlist_id'))
|
||||||
|
|
||||||
|
op.drop_table('queries')
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
"""Index for notesolours substring
|
||||||
|
|
||||||
|
Revision ID: c76e865ccb85
|
||||||
|
Revises: 33c04e3c12c8
|
||||||
|
Create Date: 2025-02-07 18:21:01.760057
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'c76e865ccb85'
|
||||||
|
down_revision = '33c04e3c12c8'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(engine_name: str) -> None:
|
||||||
|
globals()["upgrade_%s" % engine_name]()
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(engine_name: str) -> None:
|
||||||
|
globals()["downgrade_%s" % engine_name]()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade_() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('notecolours', schema=None) as batch_op:
|
||||||
|
batch_op.create_index(batch_op.f('ix_notecolours_substring'), ['substring'], unique=False)
|
||||||
|
|
||||||
|
with op.batch_alter_table('playdates', schema=None) as batch_op:
|
||||||
|
batch_op.drop_constraint('fk_playdates_track_id_tracks', type_='foreignkey')
|
||||||
|
batch_op.create_foreign_key(None, 'tracks', ['track_id'], ['id'], ondelete='CASCADE')
|
||||||
|
|
||||||
|
with op.batch_alter_table('playlist_rows', schema=None) as batch_op:
|
||||||
|
batch_op.drop_constraint('playlist_rows_ibfk_1', type_='foreignkey')
|
||||||
|
batch_op.create_foreign_key(None, 'tracks', ['track_id'], ['id'], ondelete='CASCADE')
|
||||||
|
|
||||||
|
with op.batch_alter_table('queries', schema=None) as batch_op:
|
||||||
|
batch_op.drop_constraint('fk_queries_playlist_id_playlists', type_='foreignkey')
|
||||||
|
batch_op.create_foreign_key(None, 'playlists', ['playlist_id'], ['id'], ondelete='CASCADE')
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade_() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
with op.batch_alter_table('queries', schema=None) as batch_op:
|
||||||
|
batch_op.drop_constraint(None, type_='foreignkey')
|
||||||
|
batch_op.create_foreign_key('fk_queries_playlist_id_playlists', 'playlists', ['playlist_id'], ['id'])
|
||||||
|
|
||||||
|
with op.batch_alter_table('playlist_rows', schema=None) as batch_op:
|
||||||
|
batch_op.drop_constraint(None, type_='foreignkey')
|
||||||
|
batch_op.create_foreign_key('playlist_rows_ibfk_1', 'tracks', ['track_id'], ['id'])
|
||||||
|
|
||||||
|
with op.batch_alter_table('playdates', schema=None) as batch_op:
|
||||||
|
batch_op.drop_constraint(None, type_='foreignkey')
|
||||||
|
batch_op.create_foreign_key('fk_playdates_track_id_tracks', 'tracks', ['track_id'], ['id'])
|
||||||
|
|
||||||
|
with op.batch_alter_table('notecolours', schema=None) as batch_op:
|
||||||
|
batch_op.drop_index(batch_op.f('ix_notecolours_substring'))
|
||||||
|
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user