header widths and dynamic resizing and stuff

This commit is contained in:
billy 2025-10-04 15:39:12 -04:00
parent f1d018f7ce
commit 753117dacc
2 changed files with 105 additions and 85 deletions

View File

@ -24,6 +24,7 @@ from PyQt5.QtWidgets import (
from PyQt5.QtCore import ( from PyQt5.QtCore import (
QItemSelectionModel, QItemSelectionModel,
QSortFilterProxyModel, QSortFilterProxyModel,
QTimer,
Qt, Qt,
QModelIndex, QModelIndex,
pyqtSignal, pyqtSignal,
@ -74,13 +75,13 @@ class MusicTable(QTableView):
super().__init__(parent) super().__init__(parent)
# why do i need this? # why do i need this?
self.application_window = application_window self.application_window = application_window
self.config = ConfigParser()
# Config # Config
cfg_file = ( self.config = ConfigParser()
self.cfg_file = (
Path(user_config_dir(appname="musicpom", appauthor="billypom")) Path(user_config_dir(appname="musicpom", appauthor="billypom"))
/ "config.ini" / "config.ini"
) )
_ = self.config.read(cfg_file) _ = self.config.read(self.cfg_file)
debug(f"music table config: {self.config}") debug(f"music table config: {self.config}")
# NOTE: # NOTE:
@ -125,7 +126,6 @@ class MusicTable(QTableView):
# header # header
self.horizontal_header: QHeaderView = self.horizontalHeader() self.horizontal_header: QHeaderView = self.horizontalHeader()
assert self.horizontal_header is not None # i hate look at linting errors assert self.horizontal_header is not None # i hate look at linting errors
self.horizontal_header.setStretchLastSection(False)
self.horizontal_header.setSectionResizeMode(QHeaderView.Interactive) self.horizontal_header.setSectionResizeMode(QHeaderView.Interactive)
# dumb vertical estupido # dumb vertical estupido
self.vertical_header: QHeaderView = self.verticalHeader() self.vertical_header: QHeaderView = self.verticalHeader()
@ -142,7 +142,6 @@ class MusicTable(QTableView):
# Final actions # Final actions
# self.load_music_table() # self.load_music_table()
self.setup_keyboard_shortcuts() self.setup_keyboard_shortcuts()
self.load_header_widths()
# _________________ # _________________
# | | # | |
@ -165,11 +164,26 @@ class MusicTable(QTableView):
""" """
self.focusLeaveSignal.emit() self.focusLeaveSignal.emit()
def resizeEvent(self, e: typing.Optional[QResizeEvent]) -> None: def resizeEvent(self, e: typing.Optional[QResizeEvent]) -> None:
"""Do something when the QTableView is resized""" """
Do something when the QTableView is resized
We will recalculate column widths based on the new table width,
retaining the ratio of the original column widths.
"""
super().resizeEvent(e)
if e is None: if e is None:
raise Exception raise Exception
super().resizeEvent(e) self.load_header_widths(self.saved_column_ratios)
def showEvent(self, a0):
# Restore scroll position
super().showEvent(a0)
# widths = []
# for _ in self.saved_column_ratios:
# widths.append('0.001')
# self.load_header_widths(widths)
QTimer.singleShot(0, lambda: self.load_header_widths(self.saved_column_ratios))
def paintEvent(self, e): def paintEvent(self, e):
"""Override paint event to highlight the current cell""" """Override paint event to highlight the current cell"""
@ -267,7 +281,7 @@ class MusicTable(QTableView):
_ = worker.signals.signal_result.connect(self.on_get_audio_files_recursively_finished) _ = worker.signals.signal_result.connect(self.on_get_audio_files_recursively_finished)
_ = worker.signals.signal_finished.connect(self.load_music_table) _ = worker.signals.signal_finished.connect(self.load_music_table)
if self.qapp: if self.qapp:
threadpool = self.qapp.threadpool threadpool = self.qapp.threadpool # type: ignore
threadpool.start(worker) threadpool.start(worker)
if files: if files:
self.add_files_to_library(files) self.add_files_to_library(files)
@ -327,9 +341,6 @@ class MusicTable(QTableView):
else: # Default behavior else: # Default behavior
super().keyPressEvent(e) super().keyPressEvent(e)
def showEvent(self, a0):
# Restore scroll position
super().showEvent(a0)
# ____________________ # ____________________
# | | # | |
@ -370,8 +381,8 @@ class MusicTable(QTableView):
col_count = self.model2.columnCount() col_count = self.model2.columnCount()
qtableview_width = self.size().width() qtableview_width = self.size().width()
sum_of_cols = self.horizontal_header.length() sum_of_cols = self.horizontal_header.length()
debug(f'qtable_width: {qtableview_width}') # debug(f'qtable_width: {qtableview_width}')
debug(f'sum of cols: {sum_of_cols}') # debug(f'sum of cols: {sum_of_cols}')
if sum_of_cols != qtableview_width: # check for discrepancy if sum_of_cols != qtableview_width: # check for discrepancy
if logicalIndex < col_count: # if not the last header if logicalIndex < col_count: # if not the last header
@ -448,6 +459,55 @@ class MusicTable(QTableView):
# | | # | |
# |____________________| # |____________________|
def get_current_header_width_ratios(self) -> list[str]:
"""
Get the current header widths, as ratios
"""
total_table_width = self.size().width()
column_ratios = []
for i in range(self.model2.columnCount() - 1):
column_width = self.columnWidth(i)
ratio = column_width / total_table_width
column_ratios.append(str(round(ratio, 4)))
# debug(f'get_current_header_width_ratios = {column_ratios}')
return column_ratios
def save_header_ratios(self):
"""
Saves the current header widths to memory and file, as ratios
"""
# WARNING: DOES NOT WORK and is not used.
# the same functionality is implemented in main.py closeEvent()
self.saved_column_ratios = self.get_current_header_width_ratios()
column_ratios_as_string = ",".join(self.saved_column_ratios)
self.config["table"]["column_ratios"] = column_ratios_as_string
# Save the config
try:
with open(self.cfg_file, "w") as configfile:
self.config.write(configfile)
except Exception as e:
debug(f"wtf man {e}")
debug(f"Saved column ratios: {self.saved_column_ratios}")
def load_header_widths(self, ratios: list[str] | None = None):
"""
Loads the header widths, based on saved ratios
or pass in a list of ratios to be loaded
"""
self.horizontal_header.setStretchLastSection(True)
if ratios is None:
column_ratios = self.get_current_header_width_ratios()
else:
column_ratios = ratios
total_table_width = self.size().width()
column_widths = []
for ratio in column_ratios:
column_widths.append(float(ratio) * total_table_width)
if isinstance(column_widths, list):
for i in range(self.model2.columnCount() - 1):
self.setColumnWidth(i, int(column_widths[i]))
def set_qmodel_index(self, index: QModelIndex): def set_qmodel_index(self, index: QModelIndex):
self.current_song_qmodel_index = index self.current_song_qmodel_index = index
@ -469,11 +529,11 @@ class MusicTable(QTableView):
""" """
debug('add_files_to_library()') debug('add_files_to_library()')
worker = Worker(add_files_to_database, files, None) worker = Worker(add_files_to_database, files, None)
_ = worker.signals.signal_progress.connect(self.qapp.handle_progress) _ = worker.signals.signal_progress.connect(self.qapp.handle_progress) # type: ignore
_ = worker.signals.signal_result.connect(self.on_add_files_to_database_finished) _ = worker.signals.signal_result.connect(self.on_add_files_to_database_finished)
_ = worker.signals.signal_finished.connect(self.load_music_table) _ = worker.signals.signal_finished.connect(self.load_music_table)
if self.qapp: if self.qapp:
threadpool = self.qapp.threadpool threadpool = self.qapp.threadpool # type: ignore
threadpool.start(worker) threadpool.start(worker)
else: else:
error("Application window could not be found") error("Application window could not be found")
@ -820,17 +880,6 @@ class MusicTable(QTableView):
self.proxymodel.setSourceModel(self.model2) self.proxymodel.setSourceModel(self.model2)
self.setModel(self.proxymodel) self.setModel(self.proxymodel)
def load_header_widths(self):
"""
Loads the header widths from the last application close.
"""
table_view_column_widths = str(
self.config["table"]["column_widths"]).split(",")
debug(f"loaded header widths: {table_view_column_widths}")
if not isinstance(table_view_column_widths, list):
for i in range(self.model2.columnCount() - 1):
self.setColumnWidth(i, int(table_view_column_widths[i]))
def sort_table_by_multiple_columns(self): def sort_table_by_multiple_columns(self):
""" """
Sorts the data in QTableView (self) by multiple columns Sorts the data in QTableView (self) by multiple columns

89
main.py
View File

@ -98,14 +98,14 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
# widget bits # widget bits
self.tableView: MusicTable self.tableView: MusicTable
self.tableView.saved_column_ratios: list[str] = str(self.config["table"]["column_ratios"]).split(",") # type: ignore
debug(f'AAAAA - {self.tableView.saved_column_ratios}')
self.album_art_scene: QGraphicsScene = QGraphicsScene() self.album_art_scene: QGraphicsScene = QGraphicsScene()
self.player: QMediaPlayer = MediaPlayer() self.player: QMediaPlayer = MediaPlayer()
# set index on choose song # set index on choose song
# index is the model2's row number? i guess? # index is the model2's row number? i guess?
self.probe: QAudioProbe = QAudioProbe() # Gets audio buffer data self.probe: QAudioProbe = QAudioProbe() # Gets audio buffer data
self.audio_visualizer: AudioVisualizer = AudioVisualizer( self.audio_visualizer: AudioVisualizer = AudioVisualizer(self.player, self.probe, self.PlotWidget)
self.player, self.probe, self.PlotWidget
)
self.timer: QTimer = QTimer(parent=self) # for playback slider and such self.timer: QTimer = QTimer(parent=self) # for playback slider and such
# Button styles # Button styles
@ -146,26 +146,17 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.albumGraphicsView.setFixedSize(250, 250) self.albumGraphicsView.setFixedSize(250, 250)
# Connections # Connections
self.playbackSlider.sliderReleased.connect( self.playbackSlider.sliderReleased.connect(lambda: self.player.setPosition(self.playbackSlider.value())) # sliderReleased works better than sliderMoved
lambda: self.player.setPosition(self.playbackSlider.value()) self.volumeSlider.sliderMoved[int].connect(lambda: self.on_volume_changed())
) # sliderReleased works better than sliderMoved self.speedSlider.sliderMoved.connect(lambda: self.on_speed_changed(self.speedSlider.value()))
self.volumeSlider.sliderMoved[int].connect(
lambda: self.on_volume_changed())
self.speedSlider.sliderMoved.connect(
lambda: self.on_speed_changed(self.speedSlider.value())
)
# self.speedSlider.doubleClicked.connect(lambda: self.on_speed_changed(1)) # self.speedSlider.doubleClicked.connect(lambda: self.on_speed_changed(1))
self.playButton.clicked.connect( self.playButton.clicked.connect(self.on_play_clicked) # Click to play/pause
self.on_play_clicked) # Click to play/pause
self.previousButton.clicked.connect(self.on_prev_clicked) self.previousButton.clicked.connect(self.on_prev_clicked)
self.nextButton.clicked.connect( self.nextButton.clicked.connect(self.on_next_clicked) # Click to next song
self.on_next_clicked) # Click to next song
# FILE MENU # FILE MENU
self.actionOpenFiles.triggered.connect( self.actionOpenFiles.triggered.connect(self.open_files) # Open files window
self.open_files) # Open files window self.actionNewPlaylist.triggered.connect(self.playlistTreeView.create_playlist)
self.actionNewPlaylist.triggered.connect(
self.playlistTreeView.create_playlist)
self.actionExportPlaylist.triggered.connect(self.export_playlist) self.actionExportPlaylist.triggered.connect(self.export_playlist)
# EDIT MENU # EDIT MENU
@ -175,9 +166,7 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
# QUICK ACTIONS MENU # QUICK ACTIONS MENU
self.actionScanLibraries.triggered.connect(self.scan_libraries) self.actionScanLibraries.triggered.connect(self.scan_libraries)
self.actionDeleteDatabase.triggered.connect(self.delete_database) self.actionDeleteDatabase.triggered.connect(self.delete_database)
self.actionSortColumns.triggered.connect( self.actionSortColumns.triggered.connect(self.tableView.sort_table_by_multiple_columns)
self.tableView.sort_table_by_multiple_columns
)
# QTableView # QTableView
# for drag & drop functionality # for drag & drop functionality
@ -187,36 +176,23 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
self.lineEditSearch: QLineEdit self.lineEditSearch: QLineEdit
# CONNECTIONS # CONNECTIONS
self.lineEditSearch.textTypedSignal.connect( self.lineEditSearch.textTypedSignal.connect(self.handle_search_box_text)
self.handle_search_box_text)
# tableView # tableView
self.tableView.playSignal.connect(self.play_audio_file) self.tableView.playSignal.connect(self.play_audio_file)
self.tableView.playPauseSignal.connect( self.tableView.playPauseSignal.connect(self.on_play_clicked) # Spacebar toggle play/pause signal
self.on_play_clicked
) # Spacebar toggle play/pause signal
self.tableView.handleProgressSignal.connect(self.handle_progress) self.tableView.handleProgressSignal.connect(self.handle_progress)
self.tableView.searchBoxSignal.connect( self.tableView.searchBoxSignal.connect(self.handle_search_box_visibility)
self.handle_search_box_visibility) self.tableView.playlistStatsSignal.connect(self.set_permanent_status_bar_message)
self.tableView.playlistStatsSignal.connect(
self.set_permanent_status_bar_message
)
self.tableView.load_music_table() self.tableView.load_music_table()
self.player.playlistNextSignal.connect(self.on_next_clicked) self.player.playlistNextSignal.connect(self.on_next_clicked)
# playlistTreeView # playlistTreeView
self.playlistTreeView.playlistChoiceSignal.connect( self.playlistTreeView.playlistChoiceSignal.connect(self.tableView.load_music_table)
self.tableView.load_music_table self.playlistTreeView.allSongsSignal.connect(self.tableView.load_music_table)
)
self.playlistTreeView.allSongsSignal.connect(
self.tableView.load_music_table)
# albumGraphicsView # albumGraphicsView
self.albumGraphicsView.albumArtDropped.connect( self.albumGraphicsView.albumArtDropped.connect(self.set_album_art_for_selected_songs)
self.set_album_art_for_selected_songs self.albumGraphicsView.albumArtDeleted.connect(self.delete_album_art_for_current_song)
)
self.albumGraphicsView.albumArtDeleted.connect(
self.delete_album_art_for_current_song
)
# _________________ # _________________
# | | # | |
@ -233,23 +209,22 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
def closeEvent(self, a0: QCloseEvent | None) -> None: def closeEvent(self, a0: QCloseEvent | None) -> None:
"""Save settings when closing the application""" """Save settings when closing the application"""
# MusicTable/tableView column widths # MusicTable/tableView column widths
list_of_column_widths = [] # list_of_column_widths = []
for i in range(self.tableView.model2.columnCount()): # for i in range(self.tableView.model2.columnCount()):
list_of_column_widths.append(str(self.tableView.columnWidth(i))) # list_of_column_widths.append(str(self.tableView.columnWidth(i)))
column_widths_as_string = ",".join(list_of_column_widths) # column_widths_as_string = ",".join(list_of_column_widths)
debug(f"saving column widths: {column_widths_as_string}") # debug(f"saving column widths: {column_widths_as_string}")
self.config["table"]["column_widths"] = column_widths_as_string # self.config["table"]["column_widths"] = column_widths_as_string
self.config["settings"]["volume"] = str(self.current_volume) self.config["settings"]["volume"] = str(self.current_volume)
self.config["settings"]["window_size"] = ( self.config["settings"]["window_size"] = (str(self.width()) + "," + str(self.height()))
str(self.width()) + "," + str(self.height()) self.config['table']['column_ratios'] = ",".join(self.tableView.get_current_header_width_ratios())
)
# Save the config # Save the config
try: try:
with open(self.cfg_file, "w") as configfile: with open(self.cfg_file, "w") as configfile:
self.config.write(configfile) self.config.write(configfile)
except Exception as e: except Exception as e:
debug(f"wtf man {e}") debug(f"wtf man {e}")
# auto export any playlists that want it # auto export any playlists that want it
try: try:
with DBA.DBAccess() as db: with DBA.DBAccess() as db:
@ -343,12 +318,8 @@ class ApplicationWindow(QMainWindow, Ui_MainWindow):
return return
row: int = index.row() row: int = index.row()
next_row: int = row + 1 next_row: int = row + 1
next_index: QModelIndex = self.tableView.proxymodel.index( next_index: QModelIndex = self.tableView.proxymodel.index(next_row, index.column())
next_row, index.column() next_filepath = next_index.siblingAtColumn(self.headers.db_list.index("filepath")).data()
)
next_filepath = next_index.siblingAtColumn(
self.headers.db_list.index("filepath")
).data()
if next_filepath is None: if next_filepath is None:
return return
self.play_audio_file(next_filepath) self.play_audio_file(next_filepath)