299 lines
8.0 KiB
Python
299 lines
8.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
기본 위젯 클래스 모듈
|
|
모든 커스텀 위젯의 기반 클래스를 정의합니다.
|
|
|
|
이 모듈은 다음 기능을 제공합니다:
|
|
- 공통 스타일링
|
|
- 이벤트 처리
|
|
- 로깅 통합
|
|
- 시그널 연결
|
|
"""
|
|
|
|
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QGraphicsDropShadowEffect
|
|
from PySide6.QtCore import Qt, Signal, QPropertyAnimation, QEasingCurve
|
|
from PySide6.QtGui import QColor, QFont
|
|
|
|
from core.logger import get_logger
|
|
from core.config import ConfigManager
|
|
from core.signals import GlobalSignals
|
|
|
|
# 로거 설정
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
class BaseWidget(QWidget):
|
|
"""
|
|
기본 위젯 클래스
|
|
|
|
모든 커스텀 위젯이 상속받는 기반 클래스입니다.
|
|
공통 기능과 스타일링을 제공합니다.
|
|
|
|
Attributes:
|
|
config: 설정 관리자
|
|
signals: 전역 시그널
|
|
|
|
Examples:
|
|
>>> class MyWidget(BaseWidget):
|
|
... def __init__(self, parent=None):
|
|
... super().__init__(parent)
|
|
... self.setup_ui()
|
|
"""
|
|
|
|
# 커스텀 시그널
|
|
widget_ready = Signal()
|
|
widget_error = Signal(str)
|
|
|
|
def __init__(self, parent=None):
|
|
"""
|
|
위젯 초기화
|
|
|
|
Args:
|
|
parent: 부모 위젯
|
|
"""
|
|
super().__init__(parent)
|
|
|
|
# 공통 객체 초기화
|
|
self.config = ConfigManager()
|
|
self.signals = GlobalSignals()
|
|
|
|
# 기본 설정
|
|
self._setup_base()
|
|
|
|
logger.debug(f"{self.__class__.__name__} 초기화")
|
|
|
|
def _setup_base(self):
|
|
"""기본 설정"""
|
|
# 폰트 설정
|
|
self._apply_font()
|
|
|
|
# 기본 속성
|
|
self.setAttribute(Qt.WA_StyledBackground, True)
|
|
|
|
def _apply_font(self):
|
|
"""폰트 적용"""
|
|
font = QFont(self.config.get('app', 'font_family', 'GmarketSans'))
|
|
font.setPixelSize(self.config.get('app', 'font_size', 14))
|
|
self.setFont(font)
|
|
|
|
def add_shadow(self, blur_radius: int = 20, offset: tuple = (0, 4), color: str = "#00000040"):
|
|
"""
|
|
위젯에 그림자 효과를 추가합니다.
|
|
|
|
Args:
|
|
blur_radius: 블러 반경
|
|
offset: 그림자 오프셋 (x, y)
|
|
color: 그림자 색상
|
|
"""
|
|
shadow = QGraphicsDropShadowEffect(self)
|
|
shadow.setBlurRadius(blur_radius)
|
|
shadow.setOffset(*offset)
|
|
shadow.setColor(QColor(color))
|
|
self.setGraphicsEffect(shadow)
|
|
|
|
def create_fade_animation(
|
|
self,
|
|
start_value: float = 0.0,
|
|
end_value: float = 1.0,
|
|
duration: int = 300
|
|
) -> QPropertyAnimation:
|
|
"""
|
|
페이드 애니메이션을 생성합니다.
|
|
|
|
Args:
|
|
start_value: 시작 투명도
|
|
end_value: 종료 투명도
|
|
duration: 애니메이션 시간 (ms)
|
|
|
|
Returns:
|
|
QPropertyAnimation 객체
|
|
"""
|
|
from PySide6.QtWidgets import QGraphicsOpacityEffect
|
|
|
|
opacity_effect = QGraphicsOpacityEffect(self)
|
|
self.setGraphicsEffect(opacity_effect)
|
|
|
|
animation = QPropertyAnimation(opacity_effect, b"opacity")
|
|
animation.setDuration(duration)
|
|
animation.setStartValue(start_value)
|
|
animation.setEndValue(end_value)
|
|
animation.setEasingCurve(QEasingCurve.InOutQuad)
|
|
|
|
return animation
|
|
|
|
def fade_in(self, duration: int = 300):
|
|
"""페이드 인 효과"""
|
|
anim = self.create_fade_animation(0.0, 1.0, duration)
|
|
anim.start()
|
|
|
|
def fade_out(self, duration: int = 300):
|
|
"""페이드 아웃 효과"""
|
|
anim = self.create_fade_animation(1.0, 0.0, duration)
|
|
anim.start()
|
|
|
|
def apply_theme(self, theme: str = None):
|
|
"""
|
|
테마를 적용합니다.
|
|
|
|
Args:
|
|
theme: 테마 이름 ('dark' 또는 'light')
|
|
"""
|
|
if theme is None:
|
|
theme = self.config.theme
|
|
|
|
# 자식 클래스에서 오버라이드
|
|
pass
|
|
|
|
def show_error(self, message: str):
|
|
"""
|
|
에러 메시지를 표시합니다.
|
|
|
|
Args:
|
|
message: 에러 메시지
|
|
"""
|
|
logger.error(f"{self.__class__.__name__}: {message}")
|
|
self.widget_error.emit(message)
|
|
self.signals.error_occurred.emit(self.__class__.__name__, message)
|
|
|
|
def show_status(self, message: str, timeout: int = 3000):
|
|
"""
|
|
상태 메시지를 표시합니다.
|
|
|
|
Args:
|
|
message: 상태 메시지
|
|
timeout: 표시 시간 (ms)
|
|
"""
|
|
self.signals.status_message.emit(message, timeout)
|
|
|
|
|
|
class CardWidget(BaseWidget):
|
|
"""
|
|
카드 스타일 위젯
|
|
|
|
둥근 모서리와 그림자가 있는 카드 형태의 위젯입니다.
|
|
"""
|
|
|
|
def __init__(self, parent=None, padding: int = 16, radius: int = 12):
|
|
"""
|
|
카드 위젯 초기화
|
|
|
|
Args:
|
|
parent: 부모 위젯
|
|
padding: 내부 여백
|
|
radius: 모서리 반경
|
|
"""
|
|
super().__init__(parent)
|
|
|
|
self.padding = padding
|
|
self.radius = radius
|
|
|
|
self._setup_card()
|
|
|
|
def _setup_card(self):
|
|
"""카드 스타일 설정"""
|
|
# 레이아웃 설정
|
|
self.layout = QVBoxLayout(self)
|
|
self.layout.setContentsMargins(
|
|
self.padding, self.padding,
|
|
self.padding, self.padding
|
|
)
|
|
self.layout.setSpacing(8)
|
|
|
|
# 그림자 추가
|
|
self.add_shadow()
|
|
|
|
# 스타일 적용
|
|
self._apply_card_style()
|
|
|
|
def _apply_card_style(self):
|
|
"""카드 스타일시트 적용"""
|
|
theme = self.config.theme
|
|
|
|
if theme == 'dark':
|
|
bg_color = "#1e293b"
|
|
border_color = "#334155"
|
|
else:
|
|
bg_color = "#ffffff"
|
|
border_color = "#e2e8f0"
|
|
|
|
self.setStyleSheet(f"""
|
|
CardWidget {{
|
|
background-color: {bg_color};
|
|
border: 1px solid {border_color};
|
|
border-radius: {self.radius}px;
|
|
}}
|
|
""")
|
|
|
|
|
|
class ContainerWidget(BaseWidget):
|
|
"""
|
|
컨테이너 위젯
|
|
|
|
다른 위젯들을 담는 컨테이너 역할을 합니다.
|
|
수직 또는 수평 레이아웃을 지원합니다.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
parent=None,
|
|
orientation: str = 'vertical',
|
|
spacing: int = 8,
|
|
margins: tuple = (0, 0, 0, 0)
|
|
):
|
|
"""
|
|
컨테이너 위젯 초기화
|
|
|
|
Args:
|
|
parent: 부모 위젯
|
|
orientation: 레이아웃 방향 ('vertical' 또는 'horizontal')
|
|
spacing: 위젯 간 간격
|
|
margins: 여백 (left, top, right, bottom)
|
|
"""
|
|
super().__init__(parent)
|
|
|
|
self.orientation = orientation
|
|
self.spacing = spacing
|
|
self.margins = margins
|
|
|
|
self._setup_container()
|
|
|
|
def _setup_container(self):
|
|
"""컨테이너 설정"""
|
|
if self.orientation == 'vertical':
|
|
self.layout = QVBoxLayout(self)
|
|
else:
|
|
self.layout = QHBoxLayout(self)
|
|
|
|
self.layout.setSpacing(self.spacing)
|
|
self.layout.setContentsMargins(*self.margins)
|
|
|
|
def add_widget(self, widget: QWidget, stretch: int = 0):
|
|
"""
|
|
위젯을 추가합니다.
|
|
|
|
Args:
|
|
widget: 추가할 위젯
|
|
stretch: 늘어남 비율
|
|
"""
|
|
self.layout.addWidget(widget, stretch)
|
|
|
|
def add_spacing(self, size: int):
|
|
"""
|
|
간격을 추가합니다.
|
|
|
|
Args:
|
|
size: 간격 크기
|
|
"""
|
|
self.layout.addSpacing(size)
|
|
|
|
def add_stretch(self, stretch: int = 1):
|
|
"""
|
|
늘어남 영역을 추가합니다.
|
|
|
|
Args:
|
|
stretch: 늘어남 비율
|
|
"""
|
|
self.layout.addStretch(stretch)
|
|
|
|
|