Skip to content

Commit

Permalink
feat: add option to rename videos and set custom color
Browse files Browse the repository at this point in the history
  • Loading branch information
vzhd1701 committed Dec 26, 2021
1 parent c9bbda5 commit a2cba33
Show file tree
Hide file tree
Showing 14 changed files with 85,420 additions and 84,897 deletions.
182 changes: 182 additions & 0 deletions gridplayer/dialogs/rename_dialog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QBrush, QColor, QIcon, QPainter, QPen


class QColorCircle(QtWidgets.QRadioButton):
def __init__(self, color, is_custom=False, **kwargs):
super().__init__(**kwargs)

self.color = color
self.is_custom = is_custom

circle_size = 36

self.setFixedSize(circle_size, circle_size)

def paintEvent(self, event):
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)

self.draw_selected_outline(painter)

self.draw_circle(painter)

def draw_selected_outline(self, painter):
if self.isChecked():
dot_line_pen = QPen(QBrush(QColor(Qt.black)), 2, Qt.DotLine)
painter.setPen(dot_line_pen)

one_pixel_margin_circle = self.rect().adjusted(1, 1, -1, -1)
painter.drawEllipse(one_pixel_margin_circle)

def draw_circle(self, painter):
# Draw color circle
if self.color in (Qt.white, None): # noqa: WPS510
painter.setPen(QPen(QBrush(QColor(Qt.gray)), 2))
circle_rect = self.rect().adjusted(5, 5, -5, -5)
else:
painter.setPen(Qt.NoPen)
circle_rect = self.rect().adjusted(4, 4, -4, -4)

if self.color is None:
f = painter.font()
moderately_big = 20
f.setPixelSize(moderately_big)
painter.setFont(f)
painter.drawText(self.rect(), Qt.AlignCenter, "…")
else:
painter.setBrush(self.color)

painter.drawEllipse(circle_rect)

def mousePressEvent(self, event):
if self.is_custom:
init_color = self.color or Qt.white
new_color = QtWidgets.QColorDialog.getColor(
init_color, self, "Select color"
)
if new_color.isValid():
self.color = new_color
self.update()
else:
return
self.setChecked(True)


class QColorPalette(QtWidgets.QWidget):
color_palette = (
(255, 255, 255),
(0, 0, 0),
(87, 36, 194),
(182, 41, 212),
(252, 18, 51),
(251, 95, 44),
(229, 158, 37),
(24, 168, 65),
(26, 169, 178),
(24, 133, 226),
(13, 58, 153),
)

def __init__(self, **kwargs):
super().__init__(**kwargs)

self.setAutoFillBackground(True)

self.color_widgets = {
col: QColorCircle(QColor(*col), parent=self) for col in self.color_palette
}
self.custom_color_widget = QColorCircle(None, is_custom=True, parent=self)

main_layout = QtWidgets.QHBoxLayout(self)
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
for col_widget in self.color_widgets.values():
main_layout.addWidget(col_widget)
main_layout.addWidget(self.custom_color_widget)

@property
def color(self):
for col_widget in self.color_widgets.values():
if col_widget.isChecked():
return col_widget.color
return self.custom_color_widget.color

@color.setter
def color(self, color_rgb):
if self.color_widgets.get(color_rgb):
self.color_widgets[color_rgb].setChecked(True)
else:
self.custom_color_widget.color = QColor(*color_rgb)
self.custom_color_widget.setChecked(True)


class QVideoRenameDialog(QtWidgets.QDialog):
def __init__(self, **kwargs):
super().__init__(**kwargs)

self.original_title = ""

self.title = QtWidgets.QLineEdit(self)

self.title_reset_button = QtWidgets.QPushButton("Reset", self)
self.title_reset_button.clicked.connect(self.reset_title)

self.palette = QColorPalette(parent=self)

self.buttons = self.init_buttons()

self.ui_setup()

def init_buttons(self):
buttons = QtWidgets.QDialogButtonBox(
QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel,
Qt.Horizontal,
self,
)
buttons.accepted.connect(self.accept)
buttons.rejected.connect(self.reject)

for btn in buttons.buttons():
btn.setIcon(QIcon())

return buttons

def ui_setup(self):
main_layout = QtWidgets.QVBoxLayout(self)
main_layout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)

input_line = QtWidgets.QHBoxLayout()
input_line.addWidget(self.title)
input_line.addWidget(self.title_reset_button)

main_layout.addLayout(input_line)
main_layout.addWidget(self.palette)
main_layout.addWidget(self.buttons)

def reset_title(self):
self.title.setText(self.original_title)

@classmethod
def get_edits( # noqa: WPS211
cls,
parent,
title,
orig_title,
cur_title,
cur_color,
):
dialog = cls(parent=parent)
dialog.setWindowTitle(title)

dialog.original_title = orig_title
dialog.title.setText(cur_title)
dialog.palette.color = cur_color

if dialog.exec():
new_title = dialog.title.text().strip() or cur_title
new_color = dialog.palette.color.name(QColor.HexRgb)
return new_title, new_color

return cur_title, QColor(*cur_color).name(QColor.HexRgb)
5 changes: 5 additions & 0 deletions gridplayer/player/managers/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
"icon": "close",
"func": ("active", "exit"),
},
"Rename": {
"key": "Ctrl+Shift+R",
"icon": "rename",
"func": ("active", "rename"),
},
"Add Files": {
"key": "Ctrl+A",
"icon": "add-files",
Expand Down
5 changes: 4 additions & 1 deletion gridplayer/player/managers/add_videos.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from pathlib import Path

from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QFileDialog

Expand All @@ -23,7 +25,8 @@ def cmd_add_videos(self):

if dialog.exec():
videos = [
Video(file_path=f) for f in filter_valid_files(dialog.selectedFiles())
Video(file_path=f, title=f.name)
for f in filter_valid_files(list(map(Path, dialog.selectedFiles())))
]

self.videos_added.emit(videos)
7 changes: 4 additions & 3 deletions gridplayer/player/managers/drag_n_drop.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from pathlib import Path

from PyQt5.QtCore import QEvent, QMimeData, Qt, pyqtSignal
from PyQt5.QtGui import QDrag
Expand All @@ -12,7 +13,7 @@


class DragNDropManager(ManagerBase):
playlist_dropped = pyqtSignal(str)
playlist_dropped = pyqtSignal(Path)
videos_dropped = pyqtSignal(list)

videos_swapped = pyqtSignal()
Expand Down Expand Up @@ -57,10 +58,10 @@ def dropEvent(self, event):

# Add new video
if drop_files:
if drop_files[0].endswith("gpls"):
if drop_files[0].suffix == ".gpls":
self.playlist_dropped.emit(drop_files[0])
else:
videos = [Video(file_path=f) for f in drop_files]
videos = [Video(file_path=f, title=f.name) for f in drop_files]
self.videos_dropped.emit(videos)

event.acceptProposedAction()
Expand Down
1 change: 1 addition & 0 deletions gridplayer/player/managers/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
("Speed", "Faster", "Slower", "Normal"),
("Zoom", "Zoom In", "Zoom Out", "Zoom Reset"),
("Aspect", "Aspect Fit", "Aspect Stretch", "Aspect None"),
"Rename",
],
"video_block": ["Close"],
"video_single": ["Next Video"],
Expand Down
46 changes: 23 additions & 23 deletions gridplayer/player/managers/playlist.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import logging
import os
from pathlib import Path

from PyQt5.QtCore import QDir, QEvent, pyqtSignal
from PyQt5.QtWidgets import QFileDialog, QMessageBox
Expand Down Expand Up @@ -66,24 +66,24 @@ def cmd_save_playlist(self):
if self._saved_playlist is not None:
save_path = self._saved_playlist["path"]
else:
save_path = os.path.join(QDir.homePath(), "Untitled.gpls")
save_path = Path(QDir.homePath()) / "Untitled.gpls"

logger.debug(f"Proposed playlist save path: {save_path}")

file_path = QFileDialog.getSaveFileName(
self.parent(), "Where to save playlist", save_path, "*.gpls"
file_path, _ = QFileDialog.getSaveFileName(
self.parent(), "Where to save playlist", str(save_path), "*.gpls"
)

if not file_path[0]:
if not file_path:
return

file_path = os.path.abspath(file_path[0])
file_path = Path(file_path)

# filename placeholder is not available if file doesn't exist
# problematic for new playlists, need to prevent accidental overwrite
# occurs in Flatpak, maybe in other sandboxes that use portal
if not file_path.endswith(".gpls"):
file_path = f"{file_path}.gpls"
if file_path.suffix != ".gpls":
file_path = file_path.with_suffix(".gpls")

if self._is_overwrite_denied(file_path):
return
Expand All @@ -96,42 +96,44 @@ def cmd_save_playlist(self):
}

def process_arguments(self, argv):
files = filter_valid_files(argv)
files = filter_valid_files(list(map(Path, argv)))

if not files:
self.error.emit("No supported files!")
return

if files[0].endswith("gpls"):
if files[0].suffix == ".gpls":
self.load_playlist_file(files[0])
return

playlist = Playlist(videos=[Video(file_path=f) for f in files])
videos = [Video(file_path=f, title=f.name) for f in files]

playlist = Playlist(videos=videos)

self.load_playlist(playlist)

self._saved_playlist = None

def load_playlist_file(self, filename):
def load_playlist_file(self, playlist_file: Path):
try:
playlist = Playlist.read(filename)
playlist = Playlist.read(playlist_file)
except ValueError as e:
logger.error(f"Playlist parse error: {e}")
return self.error.emit(f"Invalid playlist format!\n\n{filename}")
return self.error.emit(f"Invalid playlist format!\n\n{playlist_file}")
except FileNotFoundError:
return self.error.emit(f"File not found!\n\n{filename}")
return self.error.emit(f"File not found!\n\n{playlist_file}")

if not playlist.videos:
return self.error.emit(f"Empty or invalid playlist!\n\n{filename}")
return self.error.emit(f"Empty or invalid playlist!\n\n{playlist_file}")

self.load_playlist(playlist)

self._saved_playlist = {
"path": filename,
"path": playlist_file,
"state": hash(self._make_playlist().dumps()),
}

def load_playlist(self, playlist):
def load_playlist(self, playlist: Playlist):
self.cmd_close_playlist()

self.videos_loaded.emit(playlist.videos)
Expand Down Expand Up @@ -167,12 +169,10 @@ def check_playlist_save(self):
if ret == QMessageBox.Yes:
self.cmd_save_playlist()

def _is_overwrite_denied(self, file_path):
if os.path.isfile(file_path):
file_name = os.path.basename(file_path)

def _is_overwrite_denied(self, file_path: Path):
if file_path.is_file():
ret = QCustomMessageBox.question(
self.parent(), "Playlist", f"Do you want to overwrite {file_name}?"
self.parent(), "Playlist", f"Do you want to overwrite {file_path.name}?"
)

if ret != QMessageBox.No:
Expand Down
5 changes: 4 additions & 1 deletion gridplayer/playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def parse(cls, playlist_txt):

return playlist

def save(self, filename):
def save(self, filename: Path):
playlist_txt = self.dumps()

with open(filename, "w", encoding="utf-8") as f:
Expand Down Expand Up @@ -83,6 +83,9 @@ def _parse_videos(cls, playlist_in):
video = video_params.get(idx, Video())
video.file_path = path

if not video.title:
video.title = video.file_path.name

videos.append(video)

return videos
Expand Down
Loading

0 comments on commit a2cba33

Please sign in to comment.