Files
Dispatch/Dispatch_V0.1.1/gui/components/kanban_column.py
2026-04-29 08:18:54 +04:00

132 lines
4.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- 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)