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 if sound_type == 0: self.first_bell_file_text .setText(file_name) elif sound_type == 1: self.second_bell_file_text.setText(file_name) elif sound_type == 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