Update to 0.2.0

This commit is contained in:
2o 2024-10-18 11:38:23 +03:00
parent 9bc919459e
commit 02deb8a77f
15 changed files with 646 additions and 0 deletions

BIN
add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

BIN
apply.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

BIN
delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

BIN
edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

12
main.py Normal file
View File

@ -0,0 +1,12 @@
# this will either work flawlessly, or fail to do anything...
# if you're trying to understand this, sorry for the spaghetti code
from ui import Ui
from scheduler import Scheduler
import sys
sc = Scheduler()
ui = Ui(sc.menu_event, sc.update)
sc.set_ui_class(ui)
ui.run()

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
PySide6
playsound

BIN
save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

135
scheduler.py Normal file
View File

@ -0,0 +1,135 @@
import time, json, dataclasses
from enum import Enum
from playsound import playsound
from sound import play
class SoundType(Enum):
FIRST_BELL = 1
SECOND_BELL = 2
BREAK = 3
CUSTOM = 4
BELL_NAMES = {
SoundType.FIRST_BELL: "1-й дзвоник",
SoundType.SECOND_BELL: "2-й дзвоник",
SoundType.BREAK: "Перерва"
}
@dataclasses.dataclass
class Bell:
sound: SoundType
hour: int
minute: int
played: bool = False
# only used when sound = SoundType.CUSTOM
custom_file: str = ""
custom_name: str = ""
@dataclasses.dataclass
class CustomSound:
name: str
times: list[list[int]]
sound_file: str
@dataclasses.dataclass
class Config:
# yes, this is permanently "borrowed" from the internet
# thx to https://stackoverflow.com/questions/53632152/why-cant-dataclasses-have-mutable-defaults-in-their-class-attributes-declaratio
lessons_start: list[int] = dataclasses.field(default_factory=lambda: [8, 0])
lesson_length: int = dataclasses.field(default_factory=lambda: 40)
break_length: int = dataclasses.field(default_factory=lambda: 5)
first_bell: int = dataclasses.field(default_factory=lambda: 1)
num_lessons: int = dataclasses.field(default_factory=lambda: 12)
workdays: list[bool] = dataclasses.field(default_factory=lambda: [True, True, True, True, True, True, False])
sound_files: list[str] = dataclasses.field(default_factory=lambda: ["", "", ""])
first_bell_before_first_lesson: bool = dataclasses.field(default_factory=lambda: True)
custom_sounds: list[CustomSound] = dataclasses.field(default_factory=lambda: [])
class Scheduler:
def __init__(self) -> None:
self.bells: list[Bell] = []
self.bells_enabled: bool = True
self.load_config()
def set_ui_class(self, ui_class) -> None:
self.ui = ui_class
self.generate_bells()
self.ui.set_settings(self.config)
def apply_config(self) -> None:
self.ui.get_settings(self.config, CustomSound)
self.generate_bells()
def generate_bells(self) -> None:
self.bells = []
if not self.config.workdays[time.localtime().tm_wday]:
self.ui.set_schedule(self.get_bells_list())
return
day_minute: int = self.config.lessons_start[0] * 60 + self.config.lessons_start[1] - self.config.first_bell
for lesson_number in range(self.config.num_lessons):
if lesson_number != 0 or self.config.first_bell_before_first_lesson:
self.bells.append(Bell(SoundType.FIRST_BELL, day_minute // 60, day_minute % 60))
day_minute += self.config.first_bell
self.bells.append(Bell(SoundType.SECOND_BELL, day_minute // 60, day_minute % 60))
day_minute += self.config.lesson_length
self.bells.append(Bell(SoundType.BREAK, day_minute // 60, day_minute % 60))
day_minute += self.config.break_length - self.config.first_bell
for sound in self.config.custom_sounds:
for sound_time in sound.times:
self.bells.append(Bell(SoundType.CUSTOM, *sound_time, custom_file=sound.sound_file, custom_name=sound.name))
# so that the first bell before the first lesson can't roll time into the negatives
self.bells = [bell for bell in self.bells if bell.hour <= 23]
self.bells.sort(key=lambda sound: sound.hour * 60 + sound.minute)
self.ui.set_schedule(self.get_bells_list())
def get_bells_list(self) -> list[str]:
bells_list: list[str] = []
for bell in self.bells:
if bell.sound != SoundType.CUSTOM: bell_name: str = BELL_NAMES[bell.sound]
else: bell_name: str = '"' + bell.custom_name + '"'
bells_list.append(f"{bell.hour:02}:{bell.minute:02} - {bell_name}")
return bells_list
def menu_event(self, button) -> None:
match button:
case 0: self.apply_config()
case 1: self.save_config()
case 2: self.bells_enabled = True
case 3: self.bells_enabled = False
def update(self) -> None:
if not self.bells_enabled:
return
t = time.localtime()
for bell_n, bell in enumerate(self.bells):
if (not bell.played) and (bell.hour == t.tm_hour) and (bell.minute == t.tm_min):
bell.played = True
self.ui.select_bell(bell_n)
match bell.sound:
case SoundType.FIRST_BELL: play(self.config.sound_files[0])
case SoundType.SECOND_BELL: play(self.config.sound_files[1])
case SoundType.BREAK: play(self.config.sound_files[2])
case SoundType.CUSTOM: play(bell.custom_file)
break
def load_config(self) -> None:
try:
with open("config.json", "r") as fp:
self.config = Config(**json.load(fp))
for i in range(len(self.config.custom_sounds)):
self.config.custom_sounds[i] = CustomSound(**self.config.custom_sounds[i])
except:
# if something goes wrong, load the default values
# nothing should go wrong with the config file, if the user doesn't edit
# it manually. if that's the case - it's their fault, not mine :P
self.config = Config()
def save_config(self) -> None:
temp_config = Config()
self.ui.get_settings(temp_config, CustomSound)
with open("config.json", "w") as fp:
json.dump(dataclasses.asdict(temp_config), fp)

7
sound.py Normal file
View File

@ -0,0 +1,7 @@
import playsound
def play(file_name):
try:
playsound.playsound(file_name, block=False)
except playsound.PlaysoundException:
pass

BIN
start.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

BIN
stop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

37
ui.py Normal file
View File

@ -0,0 +1,37 @@
from PySide6 import QtWidgets, QtGui, QtCore
from windows import MainWindow, MenuActions, ToolBar, MenuBar, Tray, SoundEditorWindow
class Ui:
def __init__(self, menu_callback, periodic_task):
self.app = QtWidgets.QApplication([])
self.app.setQuitOnLastWindowClosed(False)
self.sound_editor_window = SoundEditorWindow()
self.main_window = MainWindow(self.sound_editor_window.show)
self.menu_actions = MenuActions(self.main_window, menu_callback)
self.menu_bar = MenuBar(self.main_window, self.menu_actions)
self.toolbar = ToolBar(self.main_window, self.menu_actions)
self.tray = Tray(self.main_window)
self.sound_editor_window.set_add_sound_callback(self.main_window.additional_sounds_box.add_sound)
# timer for starting bells
self.timer = QtCore.QTimer()
self.timer.timeout.connect(periodic_task)
self.timer.start(1000)
def run(self):
self.main_window.show()
self.tray.setVisible(True)
self.app.exec()
def get_settings(self, *args, **kwargs):
return self.main_window.get_settings(*args, **kwargs)
def set_settings(self, *args, **kwargs):
self.main_window.set_settings(*args, **kwargs)
def set_schedule(self, *args, **kwargs):
self.main_window.set_schedule(*args, **kwargs)
def select_bell(self, *args, **kwargs):
self.main_window.select_bell(*args, **kwargs)

277
widgets.py Normal file
View File

@ -0,0 +1,277 @@
from PySide6 import QtWidgets, QtGui, QtCore
import time
DAYS_OF_WEEK = "Понеділок Вівторок Середа Четвер П'ятниця Субота Неділя".split()
class BasicBox(QtWidgets.QScrollArea):
def __init__(self, title):
super().__init__()
self.widget = QtWidgets.QWidget()
self.setWidgetResizable(True)
self.setWidget(self.widget)
self.layout = QtWidgets.QVBoxLayout(self.widget)
font = QtGui.QFont()
font.setPointSize(16)
title = QtWidgets.QLabel(title)
title.setFont(font)
self.layout.addWidget(title)
class WidgetArray(QtWidgets.QWidget):
def __init__(self, deleted_item_callback, edit_button=False):
super().__init__()
self.deleted_item_callback = deleted_item_callback
self.main_layout = QtWidgets.QVBoxLayout(self)
self.control_widget = QtWidgets.QWidget()
self.control_layout = QtWidgets.QHBoxLayout(self.control_widget)
self.add_button = QtWidgets.QPushButton()
self.add_button.setIcon(QtGui.QIcon("add.png"))
self.add_button.setFixedSize(22, 22)
self.delete_button = QtWidgets.QPushButton()
self.delete_button.setIcon(QtGui.QIcon("delete.png"))
self.delete_button.setFixedSize(22, 22)
self.delete_button.clicked.connect(self.delete_items)
self.control_layout.addWidget(self.add_button)
self.control_layout.addWidget(self.delete_button)
if edit_button:
self.edit_button = QtWidgets.QPushButton()
self.edit_button.setIcon(QtGui.QIcon("edit.png"))
self.edit_button.setFixedSize(22, 22)
self.control_layout.addWidget(self.edit_button)
self.control_layout.addStretch(1)
self.widget_list = QtWidgets.QListWidget()
self.main_layout.addWidget(self.control_widget)
self.main_layout.addWidget(self.widget_list)
def add_item(self, widget):
item = QtWidgets.QListWidgetItem()
self.widget_list.addItem(item)
self.widget_list.setItemWidget(item, widget)
def get_items(self):
for i in range(self.widget_list.count()):
yield self.widget_list.itemWidget(self.widget_list.item(i))
def delete_items(self):
selected_items = self.widget_list.selectedItems()
if not selected_items: return
# if multiple items are selected, and the parent of this widget list keeps track of the widgets somehow,
# this makes so they are deleted in the correct order
selected_items.sort(reverse=True, key=lambda item: self.widget_list.row(item))
for item in selected_items:
row = self.widget_list.row(item)
self.widget_list.takeItem(row)
self.deleted_item_callback(row)
class BellStatusBox(BasicBox):
def __init__(self):
super().__init__("Розклад дзвінків")
self.bells_list = QtWidgets.QListWidget()
self.layout.addWidget(self.bells_list)
class ScheduleBox(BasicBox):
def __init__(self):
super().__init__("Налаштування розкладу")
self.grid_widget = QtWidgets.QWidget()
self.grid_layout = QtWidgets.QGridLayout(self.grid_widget)
self.grid_widget.setLayout(self.grid_layout)
self.first_lesson_input = QtWidgets.QTimeEdit()
self.lesson_length_input = QtWidgets.QSpinBox()
self.break_length_input = QtWidgets.QSpinBox()
self.first_bell_input = QtWidgets.QSpinBox()
self.num_lessons_input = QtWidgets.QSpinBox()
self.lesson_length_input.setRange(20, 90)
self.break_length_input.setRange(2, 59)
self.first_bell_input.setRange(1, 4)
self.num_lessons_input.setRange(1, 20)
self.break_length_input.valueChanged.connect(self.update_limits)
self.grid_layout.addWidget(QtWidgets.QLabel("Перший урок о"), 0, 0)
self.grid_layout.addWidget(QtWidgets.QLabel("Тривалість уроку:"), 1, 0)
self.grid_layout.addWidget(QtWidgets.QLabel("Перерва"), 2, 0)
self.grid_layout.addWidget(QtWidgets.QLabel("Перший дзвоник за"), 3, 0)
self.grid_layout.addWidget(QtWidgets.QLabel("Кількість уроків:"), 4, 0)
self.grid_layout.addWidget(QtWidgets.QLabel("хвилин"), 1, 2)
self.grid_layout.addWidget(QtWidgets.QLabel("хвилин"), 2, 2)
self.grid_layout.addWidget(QtWidgets.QLabel("хвилин до уроку"), 3, 2)
self.grid_layout.addWidget(self.first_lesson_input, 0, 1)
self.grid_layout.addWidget(self.lesson_length_input, 1, 1)
self.grid_layout.addWidget(self.break_length_input, 2, 1)
self.grid_layout.addWidget(self.first_bell_input, 3, 1)
self.grid_layout.addWidget(self.num_lessons_input, 4, 1)
self.first_bell_before_first_lesson_checkbox = QtWidgets.QCheckBox("Перший дзвоник перед першим уроком")
self.layout.addWidget(self.grid_widget)
self.layout.addWidget(self.first_bell_before_first_lesson_checkbox)
self.layout.addStretch(1)
def update_limits(self, value):
self.first_bell_input.setRange(1, value - 1)
class DaysSelectBox(BasicBox):
def __init__(self):
super().__init__("Робочі дні")
self.days_checkboxes = []
for day_name in DAYS_OF_WEEK:
self.days_checkboxes.append(QtWidgets.QCheckBox(day_name))
self.layout.addWidget(self.days_checkboxes[-1])
self.layout.addStretch(1)
class AdditionalSoundsBox(BasicBox):
def __init__(self, show_sound_diag):
super().__init__("Додаткові звуки")
self.show_sound_diag = show_sound_diag
self.sound_list = WidgetArray(self.deleted_item, True)
self.sound_list.add_button.clicked.connect(lambda: self.show_sound_diag())
self.sound_list.edit_button.clicked.connect(self.edit_sound)
self.layout.addWidget(self.sound_list)
self.sounds = []
self.editing_sound = 0
def add_sound(self, name, times, sound_file, edit_n=None):
if edit_n is None:
self.sounds.append([name, times, sound_file])
self.sound_list.add_item(QtWidgets.QLabel(name))
else:
self.sounds[edit_n] = [name, times, sound_file]
self.sound_list.widget_list.itemWidget(self.sound_list.widget_list.item(edit_n)).setText(name)
def deleted_item(self, n):
del self.sounds[n]
def edit_sound(self):
edit_n = self.sound_list.widget_list.currentRow()
sound = self.sounds[edit_n]
self.show_sound_diag(edit_n, *sound)
class StatusBox(BasicBox):
def __init__(self):
super().__init__("Стан")
self.grid_widget = QtWidgets.QWidget()
self.grid_layout = QtWidgets.QGridLayout(self.grid_widget)
self.grid_widget.setLayout(self.grid_layout)
self.day_of_week_widget = QtWidgets.QLabel()
self.current_time_widget = QtWidgets.QLabel()
self.uptime_widget = QtWidgets.QLabel()
self.grid_layout.addWidget(QtWidgets.QLabel("День тижня:"), 0, 0)
self.grid_layout.addWidget(self.day_of_week_widget, 0, 1)
self.grid_layout.addWidget(QtWidgets.QLabel("Поточний час:"), 1, 0)
self.grid_layout.addWidget(self.current_time_widget, 1, 1)
self.grid_layout.addWidget(QtWidgets.QLabel("Зі запуску:"), 2, 0)
self.grid_layout.addWidget(self.uptime_widget, 2, 1)
self.layout.addWidget(self.grid_widget)
self.layout.addStretch(1)
self.uptime_timer = QtCore.QElapsedTimer()
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.update)
self.uptime_timer.start()
self.timer.start(1000)
self.update()
def update(self):
t = time.localtime()
self.day_of_week_widget.setText(DAYS_OF_WEEK[t.tm_wday])
self.current_time_widget.setText(f"{t.tm_hour:02}:{t.tm_min:02}:{t.tm_sec:02}")
seconds = self.uptime_timer.elapsed() / 1000
minutes = seconds / 60
hours = minutes / 60
days = hours / 24
self.uptime_widget.setText(f"{int(days)} днів, {int(hours % 24):02}:{int(minutes % 60):02}:{int(seconds % 60):02}")
class SoundFilesBox(BasicBox):
def __init__(self):
super().__init__("Звуки")
self.grid_widget = QtWidgets.QWidget()
self.grid_layout = QtWidgets.QGridLayout(self.grid_widget)
self.grid_widget.setLayout(self.grid_layout)
self.first_bell_file_text = QtWidgets.QLabel()
self.second_bell_file_text = QtWidgets.QLabel()
self.break_file_text = QtWidgets.QLabel()
self.first_bell_file_button = QtWidgets.QPushButton("Огляд")
self.second_bell_file_button = QtWidgets.QPushButton("Огляд")
self.break_file_button = QtWidgets.QPushButton("Огляд")
self.first_bell_file_button .clicked.connect(lambda: self.file_select_diag(0))
self.second_bell_file_button.clicked.connect(lambda: self.file_select_diag(1))
self.break_file_button .clicked.connect(lambda: self.file_select_diag(2))
self.grid_layout.addWidget(QtWidgets.QLabel("Перший дзвоник:"), 0, 0)
self.grid_layout.addWidget(QtWidgets.QLabel("Другий дзвоник:"), 1, 0)
self.grid_layout.addWidget(QtWidgets.QLabel("Перерва:"), 2, 0)
self.grid_layout.addWidget(self.first_bell_file_text, 0, 1)
self.grid_layout.addWidget(self.second_bell_file_text, 1, 1)
self.grid_layout.addWidget(self.break_file_text, 2, 1)
self.grid_layout.addWidget(self.first_bell_file_button, 0, 2)
self.grid_layout.addWidget(self.second_bell_file_button, 1, 2)
self.grid_layout.addWidget(self.break_file_button, 2, 2)
self.layout.addWidget(self.grid_widget)
self.layout.addStretch(1)
def file_select_diag(self, sound_type):
file_name, _ = QtWidgets.QFileDialog.getOpenFileName(self.grid_widget, "SBC - Відкрити файл", "", "Підтримувані файли (*.wav *.mp3 *.flac)")
if file_name is None:
return
match sound_type:
case 0: self.first_bell_file_text .setText(file_name)
case 1: self.second_bell_file_text.setText(file_name)
case 2: self.break_file_text .setText(file_name)
class SoundEditorBox(BasicBox):
def __init__(self, add_sound_callback, quit_callback):
super().__init__("Редактор звуку")
self.add_sound_callback = add_sound_callback
self.quit_callback = quit_callback
self.time_select_widget = WidgetArray(lambda _: None)
self.sound_name_input = QtWidgets.QLineEdit()
self.save_button = QtWidgets.QPushButton("Зберегти")
self.time_select_widget.add_button.clicked.connect(lambda: self.time_select_widget.add_item(QtWidgets.QTimeEdit()))
self.save_button.clicked.connect(self.save)
self.file_select_widget = QtWidgets.QWidget()
self.file_select_layout = QtWidgets.QHBoxLayout(self.file_select_widget)
self.file_name_select_text = QtWidgets.QLabel()
self.file_name_select_button = QtWidgets.QPushButton("Огляд")
self.file_name_select_button.clicked.connect(self.file_select_diag)
self.file_select_layout.addWidget(self.file_name_select_text)
self.file_select_layout.addWidget(self.file_name_select_button)
self.file_select_layout.addStretch(1)
self.layout.addWidget(self.sound_name_input)
self.layout.addWidget(self.time_select_widget)
self.layout.addWidget(self.file_select_widget)
self.layout.addStretch(1)
self.layout.addWidget(self.save_button)
self.edit_n = None
def file_select_diag(self):
file_name, _ = QtWidgets.QFileDialog.getOpenFileName(self.file_select_widget, "SBC - Відкрити файл", "", "Підтримувані файли (*.wav *.mp3 *.flac)")
if file_name is None:
return
self.file_name_select_text.setText(file_name)
def save(self):
self.add_sound_callback(
self.sound_name_input.text(),
[[item.time().hour(), item.time().minute()] for item in self.time_select_widget.get_items()],
self.file_name_select_text.text(),
self.edit_n
)
self.clear_edit()
self.quit_callback()
def clear_edit(self):
self.sound_name_input.setText("")
for i in range(self.time_select_widget.widget_list.count()):
self.time_select_widget.widget_list.takeItem(0)
self.edit_n = None

176
windows.py Normal file
View File

@ -0,0 +1,176 @@
from PySide6 import QtWidgets, QtGui, QtCore
from widgets import BellStatusBox, ScheduleBox, DaysSelectBox, AdditionalSoundsBox, StatusBox, SoundFilesBox, SoundEditorBox
import sys
VERSION = "0.2.0"
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, show_sound_diag):
super().__init__()
self.setWindowTitle("SBC - Головне вікно")
self.setWindowIcon(QtGui.QIcon("icon.png"))
self.setMinimumSize(800, 768)
self.main_widget = QtWidgets.QWidget()
self.main_layout = QtWidgets.QGridLayout(self.main_widget)
self.bell_status_box = BellStatusBox()
self.schedule_box = ScheduleBox()
self.days_select_box = DaysSelectBox()
self.additional_sounds_box = AdditionalSoundsBox(show_sound_diag)
self.status_box = StatusBox()
self.sound_files_box = SoundFilesBox()
self.main_layout.addWidget(self.bell_status_box, 0, 0, 3, 1)
self.main_layout.addWidget(self.schedule_box, 0, 1, 1, 1)
self.main_layout.addWidget(self.days_select_box, 1, 1, 1, 1)
self.main_layout.addWidget(self.additional_sounds_box, 2, 1, 1, 1)
self.main_layout.addWidget(self.status_box, 0, 2, 1, 1)
self.main_layout.addWidget(self.sound_files_box, 1, 2, 1, 1)
self.setCentralWidget(self.main_widget)
def get_settings(self, config, CustomSound):
first_lesson_input = self.schedule_box.first_lesson_input.time()
config.lessons_start = [first_lesson_input.hour(), first_lesson_input.minute()]
config.lesson_length = self.schedule_box.lesson_length_input.value()
config.break_length = self.schedule_box.break_length_input .value()
config.first_bell = self.schedule_box.first_bell_input .value()
config.num_lessons = self.schedule_box.num_lessons_input .value()
config.first_bell_before_first_lesson = self.schedule_box.first_bell_before_first_lesson_checkbox.isChecked()
config.workdays = [checkbox.isChecked() for checkbox in self.days_select_box.days_checkboxes]
config.sound_files = [
self.sound_files_box.first_bell_file_text .text(),
self.sound_files_box.second_bell_file_text .text(),
self.sound_files_box.break_file_text .text()
]
config.custom_sounds = [CustomSound(*sound) for sound in self.additional_sounds_box.sounds]
def set_settings(self, config):
self.schedule_box.first_lesson_input .setTime (QtCore.QTime(*config.lessons_start))
self.schedule_box.lesson_length_input.setValue(config.lesson_length)
self.schedule_box.break_length_input .setValue(config.break_length)
self.schedule_box.first_bell_input .setValue(config.first_bell)
self.schedule_box.num_lessons_input .setValue(config.num_lessons)
self.schedule_box.first_bell_before_first_lesson_checkbox.setChecked(config.first_bell_before_first_lesson)
for i in range(0, 7): self.days_select_box.days_checkboxes[i].setChecked(config.workdays[i])
self.sound_files_box.first_bell_file_text .setText(config.sound_files[0])
self.sound_files_box.second_bell_file_text .setText(config.sound_files[1])
self.sound_files_box.break_file_text .setText(config.sound_files[2])
self.additional_sounds_box.sounds = [[sound.name, sound.times, sound.sound_file] for sound in config.custom_sounds]
for sound in config.custom_sounds: self.additional_sounds_box.sound_list.add_item(QtWidgets.QLabel(sound.name))
def set_schedule(self, bells):
self.bell_status_box.bells_list.clear()
for bell in bells:
self.bell_status_box.bells_list.addItem(bell)
def select_bell(self, bell_n):
self.bell_status_box.bells_list.setCurrentItem(self.bell_status_box.bells_list.item(bell_n))
class MenuActions:
def __init__(self, window, callback):
self.window = window
self.callback = callback
self.button_apply = QtGui.QAction(QtGui.QIcon("apply.png"), "Застосувати", window)
self.button_save = QtGui.QAction(QtGui.QIcon("save.png"), "Зберегти налаштування", window)
self.button_start = QtGui.QAction(QtGui.QIcon("start.png"), "Запустити дзвоники", window)
self.button_stop = QtGui.QAction(QtGui.QIcon("stop.png"), "Зупинити все", window)
self.button_about = QtGui.QAction( "Про програму", window)
self.button_start.setEnabled(False)
self.button_apply.triggered.connect(lambda: self.handle_button(0))
self.button_save .triggered.connect(lambda: self.handle_button(1))
self.button_start.triggered.connect(lambda: self.handle_button(2))
self.button_stop .triggered.connect(lambda: self.handle_button(3))
self.button_about.triggered.connect(lambda: self.handle_button(4))
def handle_button(self, button):
match button:
case 0 | 1 | 2 | 3:
self.callback(button)
match button:
case 0: QtWidgets.QMessageBox.information(self.window, "SBC - Інформація", "Налаштування застосовано!")
case 1: QtWidgets.QMessageBox.information(self.window, "SBC - Інформація", "Налаштування збережено!")
case 2:
self.button_start.setEnabled(False)
self.button_stop .setEnabled(True)
QtWidgets.QMessageBox.information(self.window, "SBC - Інформація", "Дзвінки запущено. Якщо ви налаштували щось не так, самі винні!")
case 3:
self.button_start.setEnabled(True)
self.button_stop .setEnabled(False)
QtWidgets.QMessageBox.information(self.window, "SBC - Інформація", "Дзвінки зупинено. Щось пішло не так, еге ж? Піди і виправи це негайно!")
case 4: QtWidgets.QMessageBox.information(self.window, "SBC - Про програму", \
f"SBC {VERSION}\nАвтор: 2o\nTelegram: @xfdtw\nDiscord: @2o___\nЯкщо щось не зрозуміло/не працює пишіть туди.")
class ToolBar(QtWidgets.QToolBar):
def __init__(self, window, menu_actions):
super().__init__("Toolbar")
window.addToolBar(self)
self.setIconSize(QtCore.QSize(16, 16))
self.addAction(menu_actions.button_apply)
self.addAction(menu_actions.button_save)
self.addSeparator()
self.addAction(menu_actions.button_start)
self.addAction(menu_actions.button_stop)
class MenuBar(QtWidgets.QMenuBar):
def __init__(self, window, menu_actions):
super().__init__()
window.setMenuBar(self)
self.settings_menu = self.addMenu("&Налаштування")
self.bells_menu = self.addMenu("&Дзвінки")
self.help_menu = self.addMenu("Д&опомога")
self.settings_menu.addAction(menu_actions.button_apply)
self.settings_menu.addAction(menu_actions.button_save)
self.bells_menu.addAction(menu_actions.button_start)
self.bells_menu.addAction(menu_actions.button_stop)
self.help_menu.addAction(menu_actions.button_about)
class Tray(QtWidgets.QSystemTrayIcon):
def __init__(self, window):
super().__init__()
self.window = window
self.setIcon(QtGui.QIcon("icon.png"))
self.setVisible(True)
self.menu = QtWidgets.QMenu(self.window)
open_window = QtGui.QAction("Показати головне вікно", self)
close_all = QtGui.QAction("Вийти", self)
open_window.triggered.connect(self.window.show)
close_all.triggered.connect(self.close_all_diag)
self.menu.addAction(open_window)
self.menu.addAction(close_all)
self.setContextMenu(self.menu)
def close_all_diag(self):
if QtWidgets.QMessageBox.question(self.window, "SBC - Вихід", \
"Ви дійсно хочете вийти з програми? Після цього дітки кричатимуть чого в них уроки по 5 годин...", \
QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No) == QtWidgets.QMessageBox.StandardButton.Yes:
sys.exit()
class SoundEditorWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("SBC - Редактор звуків")
self.setWindowIcon(QtGui.QIcon("icon.png"))
self.setMinimumSize(256, 384)
def set_add_sound_callback(self, add_sound_callback):
self.sound_editor_box = SoundEditorBox(add_sound_callback, self.hide)
self.setCentralWidget(self.sound_editor_box)
def show(self, edit_n=None, name="", times=[], sound_file=""):
self.sound_editor_box.edit_n = edit_n
self.sound_editor_box.sound_name_input.setText(name)
for sound_time in times:
self.sound_editor_box.time_select_widget \
.add_item(QtWidgets.QTimeEdit(QtCore.QTime(*sound_time)))
self.sound_editor_box.file_name_select_text.setText(sound_file)
super().show()
def closeEvent(self, *args, **kwargs):
self.sound_editor_box.clear_edit()
super().closeEvent(*args, **kwargs)