diff options
Diffstat (limited to 'todo/gui/tasks/form')
-rw-r--r-- | todo/gui/tasks/form/__init__.py | 0 | ||||
-rw-r--r-- | todo/gui/tasks/form/state.py | 100 | ||||
-rw-r--r-- | todo/gui/tasks/form/widget.py | 184 |
3 files changed, 284 insertions, 0 deletions
diff --git a/todo/gui/tasks/form/__init__.py b/todo/gui/tasks/form/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/todo/gui/tasks/form/__init__.py diff --git a/todo/gui/tasks/form/state.py b/todo/gui/tasks/form/state.py new file mode 100644 index 0000000..33b0873 --- /dev/null +++ b/todo/gui/tasks/form/state.py @@ -0,0 +1,100 @@ +from PyQt5 import QtCore +from typing import Optional + +from todo.model.task import ValidTaskForm +from todo.model.difficulty import Difficulty +from todo.model.priority import Priority +import todo.gui.tasks.duration +import todo.gui.tags.list + +class TaskFormEdition: + def __init__( + self, + name, + name_signal, + duration, + duration_signal, + difficulty, + difficulty_signal, + priority, + priority_signal, + tags_signal: todo.gui.tags.list.SelectionSignal, + description, + description_signal): + + self._name = name + self._duration = duration + self._difficulty = difficulty + self._priority = priority + self._tags = [] + self._description = description + self._signal = ValidTaskFormSignal() + + name_signal.connect(lambda n: self.on_name_signal(n)) + duration_signal.connect(lambda d: self.on_duration_signal(d)) + difficulty_signal.connect(lambda d: self.on_difficulty_signal(d)) + priority_signal.connect(lambda p: self.on_priority_signal(p)) + tags_signal.connect(lambda ts: self.on_tags_signal(ts)) + description_signal.connect(lambda d: self.on_description_signal(d)) + + def get(self) -> Optional[ValidTaskForm]: + name = self._name.strip() + duration = todo.gui.tasks.duration.parse(self._duration) + difficulty = self._difficulty + priority = self._priority + description = self._description.strip() + + if name and duration != None: + return ValidTaskForm( + name = name, + duration = duration, + difficulty = difficulty, + priority = priority, + tags = self._tags, + description = description) + else: + return None + + def on_name_signal(self, name: str): + self._name = name + self.emit() + + def on_duration_signal(self, duration: str): + self._duration = duration + self.emit() + + def on_difficulty_signal(self, index: int): + self._difficulty = Difficulty(index) + self.emit() + + def on_priority_signal(self, index: int): + self._priority = Priority(index) + self.emit() + + def on_tags_signal(self, tags: [int]): + self._tags = tags + self.emit() + + def on_description_signal(self, description: str): + self._description = description + self.emit() + + def emit(self): + validForm = self.get() + if validForm: + self._signal.emit(validForm) + + def signal(self): + return self._signal + +class ValidTaskFormSignal(QtCore.QObject): + _signal = QtCore.pyqtSignal(ValidTaskForm, name = "validTaskForm") + + def __init__(self): + QtCore.QObject.__init__(self) + + def emit(self, form: Optional[ValidTaskForm]): + self._signal.emit(form) + + def connect(self, f): + self._signal.connect(f) diff --git a/todo/gui/tasks/form/widget.py b/todo/gui/tasks/form/widget.py new file mode 100644 index 0000000..15be21b --- /dev/null +++ b/todo/gui/tasks/form/widget.py @@ -0,0 +1,184 @@ +from PyQt5 import QtWidgets, QtCore +from typing import Optional, Tuple, List, Any + +from todo.model.task import Task, ValidTaskForm +from todo.model.tag import Tag +from todo.model import difficulty, priority +import todo.gui.icon +import todo.gui.tasks.form.state +import todo.gui.tasks.duration +import todo.gui.tags.list + +class TextEditSignal(QtCore.QObject): + _signal = QtCore.pyqtSignal(str, name = "textEdit") + + def __init__(self): + QtCore.QObject.__init__(self) + + def emit(self, text: str): + self._signal.emit(text) + + def connect(self, f): + self._signal.connect(f) + +def widget( + parent: QtWidgets.QWidget, + action_title: str, + task: Task, + tags: List[int], + on_validated, + on_cancel): + + widget = QtWidgets.QWidget(parent) + layout = QtWidgets.QVBoxLayout(widget) + widget.setLayout(layout) + + grid = QtWidgets.QWidget(widget) + layout.addWidget(grid) + grid_layout = QtWidgets.QGridLayout(grid) + grid.setLayout(grid_layout) + + init_name = task.name if task is not None else "" + name_input = line_edit(grid, grid_layout, 0, "Name", init_name) + + init_duration = todo.gui.tasks.duration.format(task.duration) if task is not None else "" + duration_input = line_edit(grid, grid_layout, 1, "Duration", init_duration) + + init_difficulty = task.difficulty if task is not None else difficulty.Difficulty.NORMAL + difficulty_input = combo_box( + grid, + grid_layout, + 3, + "Difficulty", + [difficulty.format(d) for d in difficulty.values], + int(init_difficulty)) + + init_priority = task.priority if task is not None else priority.Priority.MIDDLE + priority_input = combo_box( + grid, + grid_layout, + 4, + "Priority", + [priority.format(d) for d in priority.values], + int(init_priority)) + + (tags_list_widget, tags_signal) = tags_selection(widget, tags) + layout.addWidget(tags_list_widget) + + init_description = task.description if task is not None else "" + (description_input, description_signal) = text_edit(widget, "Description", init_description) + layout.addWidget(description_input) + + task_form_edition = todo.gui.tasks.form.state.TaskFormEdition( + init_name, + name_input.textChanged, + init_duration, + duration_input.textChanged, + init_difficulty, + difficulty_input.currentIndexChanged, + init_priority, + priority_input.currentIndexChanged, + tags_signal, + init_description, + description_signal) + + def on_validate(): + form = task_form_edition.get() + if form: + on_validated(form) + + layout.addWidget(buttons( + parent = widget, + action_title = action_title, + task_form_signal = task_form_edition.signal(), + on_validate = on_validate, + on_cancel = on_cancel)) + + return widget + +def line_edit( + parent, + layout: QtWidgets.QGridLayout, + n: int, + label: str, + default_value: str) -> QtWidgets.QLineEdit: + + label = QtWidgets.QLabel(label, parent) + layout.addWidget(label, n, 0) + + edit = QtWidgets.QLineEdit(parent) + if default_value != None: + edit.setText(default_value) + layout.addWidget(edit, n, 1) + + return edit + +def combo_box( + parent, + layout: QtWidgets.QGridLayout, + n: int, + label: str, + values: List[str], + default_value: int) -> QtWidgets.QComboBox: + + label = QtWidgets.QLabel(label, parent) + layout.addWidget(label, n, 0) + + box = QtWidgets.QComboBox(parent) + for value in values: + box.addItem(value) + if default_value != None: + box.setCurrentIndex(default_value) + layout.addWidget(box, n, 1) + + return box + +def tags_selection(parent, init_tags: List[int]) -> QtWidgets.QWidget: + return todo.gui.tags.list.widget(parent, init_tags) + +def text_edit( + parent, + label: str, + default_value: str) -> Tuple[QtWidgets.QWidget, TextEditSignal]: + + widget = QtWidgets.QWidget(parent) + layout = QtWidgets.QVBoxLayout(widget) + + signal = TextEditSignal() + + label = QtWidgets.QLabel(label, parent) + layout.addWidget(label) + + edit = QtWidgets.QTextEdit(parent) + if default_value != None: + edit.insertPlainText(default_value) + layout.addWidget(edit) + + edit.textChanged.connect(lambda: signal.emit(edit.toPlainText())) + + return (widget, signal) + +def buttons(parent, action_title, task_form_signal, on_validate, on_cancel): + widget = QtWidgets.QWidget(parent) + layout = QtWidgets.QHBoxLayout(widget) + + validate = QtWidgets.QPushButton(action_title, widget) + validate.setDisabled(True) + validate.setIcon(todo.gui.icon.dialog_ok(validate.style())) + validate.clicked.connect(on_validate); + layout.addWidget(validate) + + def on_task_form_signal(form: Optional[ValidTaskForm]): + if form: + validate.setEnabled(True) + else: + validate.setDisabled(True) + + task_form_signal.connect(on_task_form_signal) + + cancel = QtWidgets.QPushButton("cancel", widget) + cancel.setIcon(todo.gui.icon.dialog_cancel(cancel.style())) + cancel.clicked.connect(on_cancel) + layout.addWidget(cancel) + + return widget |