Add Dispatch_V0.1.1
This commit is contained in:
131
Dispatch_V0.1.1/gui/components/kanban_column.py
Normal file
131
Dispatch_V0.1.1/gui/components/kanban_column.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# gui/components/kanban_column.py
|
||||
|
||||
"""Переиспользуемая колонка для канбан-доски."""
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from PySide6.QtCore import Signal
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from gui.components.kanban_card import KanbanCard
|
||||
from gui.components.label import Label
|
||||
from gui.components.springs import VSpring
|
||||
from gui.containers.h_container import HContainer
|
||||
from gui.containers.s_container import SContainer
|
||||
from gui.containers.scroll_container import ScrollContainer
|
||||
from gui.containers.v_container import VContainer
|
||||
|
||||
|
||||
class KanbanColumn(SContainer):
|
||||
"""Вертикальная колонка канбан-доски с заголовком и карточками."""
|
||||
|
||||
card_clicked = Signal(object)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
column_id: object,
|
||||
title: str = "",
|
||||
color: str = "#DFE1E6",
|
||||
style: str = "KANBAN_COLUMN",
|
||||
parent: Optional[QWidget] = None,
|
||||
):
|
||||
super().__init__(
|
||||
width_percent=20,
|
||||
margin=[4, 0, 4, 0],
|
||||
spacing=0,
|
||||
style=style,
|
||||
content_fit=True,
|
||||
parent=parent,
|
||||
)
|
||||
self._column_id = column_id
|
||||
self._color = color
|
||||
self._cards: List[KanbanCard] = []
|
||||
self._build_ui(title, color)
|
||||
|
||||
@property
|
||||
def column_id(self) -> object:
|
||||
"""Идентификатор колонки."""
|
||||
return self._column_id
|
||||
|
||||
@property
|
||||
def card_count(self) -> int:
|
||||
"""Количество карточек в колонке."""
|
||||
return len(self._cards)
|
||||
|
||||
def set_title(self, text: str) -> None:
|
||||
"""Установить заголовок колонки."""
|
||||
self._title_label.set_text(text)
|
||||
|
||||
def update_counter(self) -> None:
|
||||
"""Обновить текст счётчика."""
|
||||
self._counter_label.set_text(str(len(self._cards)))
|
||||
|
||||
def add_card(self, card: KanbanCard) -> None:
|
||||
"""Добавить карточку в колонку перед нижней пружиной."""
|
||||
card.card_clicked.connect(self.card_clicked.emit)
|
||||
self._card_container.insert_widget(len(self._cards), card)
|
||||
self._cards.append(card)
|
||||
self.update_counter()
|
||||
|
||||
def remove_card(self, card_id: object) -> Optional[KanbanCard]:
|
||||
"""Удалить карточку по ID. Возвращает удалённую карточку или None."""
|
||||
for card in self._cards:
|
||||
if card.card_id == card_id:
|
||||
self._cards.remove(card)
|
||||
self._detach_card(card)
|
||||
self.update_counter()
|
||||
return card
|
||||
return None
|
||||
|
||||
def clear_cards(self) -> None:
|
||||
"""Удалить все карточки из колонки."""
|
||||
for card in list(self._cards):
|
||||
self._detach_card(card)
|
||||
self._cards.clear()
|
||||
self.update_counter()
|
||||
|
||||
def get_card(self, card_id: object) -> Optional[KanbanCard]:
|
||||
"""Получить карточку по ID."""
|
||||
for card in self._cards:
|
||||
if card.card_id == card_id:
|
||||
return card
|
||||
return None
|
||||
|
||||
def _build_ui(self, title: str, color: str) -> None:
|
||||
header = HContainer(
|
||||
height_percent=6,
|
||||
margin=[8, 6, 8, 2],
|
||||
parent=self,
|
||||
)
|
||||
|
||||
color_strip = QWidget()
|
||||
color_strip.setFixedWidth(4)
|
||||
color_strip.setFixedHeight(16)
|
||||
color_strip.setStyleSheet(
|
||||
f"background-color: {color}; border: none; border-radius: 2px;"
|
||||
)
|
||||
header.add_widget(color_strip)
|
||||
|
||||
self._title_label = Label(title, style="KANBAN_COLUMN_HEADER")
|
||||
header.add_widget(self._title_label)
|
||||
header.add_stretch()
|
||||
|
||||
self._counter_label = Label("0", style="KANBAN_COUNTER")
|
||||
self._counter_label.set_fixed_size(24, 24)
|
||||
header.add_widget(self._counter_label)
|
||||
|
||||
self._scroll = ScrollContainer(
|
||||
orientation="v",
|
||||
spacing=0,
|
||||
content_margins=[0, 2, 0, 2],
|
||||
vertical_scroll_bar_policy="as_needed",
|
||||
horizontal_scroll_bar_policy="always_off",
|
||||
parent=self,
|
||||
)
|
||||
self._card_container = VContainer(spacing=2, parent=self._scroll)
|
||||
self._card_container.add_widget(VSpring())
|
||||
|
||||
def _detach_card(self, card: KanbanCard) -> None:
|
||||
self._card_container.remove_widget(card)
|
||||
card.setParent(None)
|
||||
Reference in New Issue
Block a user