""" Styles Module Centralized stylesheet definitions for the application. """ from utils.config import UI_COLORS # ==================== COLOR CONSTANTS ==================== # Export COLORS dictionary for tab modules COLORS = { # Primary colors 'primary': '#3498db', 'primary_dark': '#2c3e50', 'primary_light': '#34495e', # Status colors 'success': '#27ae60', 'warning': '#f39c12', 'error': '#e74c3c', 'info': '#3498db', # Background colors 'bg_light': '#f8f9fa', 'bg_white': '#ffffff', 'bg_dark': '#2c3e50', 'card_bg': '#ffffff', # Text colors 'text_primary': '#2c3e50', 'text_secondary': '#7f8c8d', 'text_light': '#bdc3c7', # Border colors 'border': '#ddd', 'border_light': '#ecf0f1', # Phase 8: Classification colors 'ripeness_unripe': '#95a5a6', 'ripeness_midripe': '#f39c12', 'ripeness_ripe': '#27ae60', 'ripeness_overripe': '#e74c3c', # Phase 8: Panel header colors 'panel_rgb': '#3498db', 'panel_multispectral': '#8e44ad', 'panel_audio': '#16a085', 'panel_results': '#27ae60', 'panel_control': '#34495e', # Phase 8: Status indicators 'status_online': '#27ae60', 'status_offline': '#e74c3c', 'status_processing': '#f39c12', } # Export STYLES dictionary for common button styles STYLES = { 'button_primary': f""" QPushButton {{ background-color: {COLORS['primary']}; border: 2px solid {COLORS['primary']}; border-radius: 8px; color: white; font-weight: bold; font-size: 14px; padding: 10px 20px; }} QPushButton:hover {{ background-color: #2980b9; }} QPushButton:pressed {{ background-color: #2471a3; }} QPushButton:disabled {{ background-color: {COLORS['text_secondary']}; border-color: {COLORS['text_secondary']}; }} """, 'button_success': f""" QPushButton {{ background-color: {COLORS['success']}; border: 2px solid {COLORS['success']}; border-radius: 8px; color: white; font-weight: bold; font-size: 14px; padding: 10px 20px; }} QPushButton:hover {{ background-color: #229954; }} QPushButton:pressed {{ background-color: #1e8449; }} """, } # ==================== MAIN WINDOW STYLES ==================== MAIN_WINDOW_STYLE = f""" QMainWindow {{ background-color: {UI_COLORS['bg_light']}; }} """ # ==================== GROUP BOX STYLES ==================== GROUP_BOX_STYLE = f""" QGroupBox {{ font-weight: bold; font-size: 16px; border: 2px solid #ddd; border-radius: 5px; margin-top: 10px; padding-top: 10px; background-color: {UI_COLORS['bg_white']}; }} QGroupBox::title {{ subcontrol-origin: margin; left: 10px; padding: 0 10px 0 10px; color: {UI_COLORS['text_dark']}; background-color: {UI_COLORS['bg_panel']}; }} """ # ==================== BUTTON STYLES ==================== def get_button_style( bg_color: str, hover_color: str, pressed_color: str = None, border_color: str = None, text_color: str = "white" ) -> str: """ Generate a button stylesheet with the given colors. Args: bg_color: Background color hover_color: Hover state color pressed_color: Pressed state color (defaults to hover_color) border_color: Border color (defaults to hover_color) text_color: Text color (defaults to white) Returns: str: Complete button stylesheet """ if pressed_color is None: pressed_color = hover_color if border_color is None: border_color = hover_color return f""" QPushButton {{ background-color: {bg_color}; border: 2px solid {border_color}; border-radius: 8px; color: {text_color}; font-weight: bold; font-size: 16px; padding: 15px; }} QPushButton:hover {{ background-color: {hover_color}; }} QPushButton:pressed {{ background-color: {pressed_color}; }} """ RIPENESS_BUTTON_STYLE = get_button_style( UI_COLORS['btn_green'], UI_COLORS['btn_green_hover'], "#1e8449" ) QUALITY_BUTTON_STYLE = get_button_style( UI_COLORS['btn_blue'], UI_COLORS['btn_blue_hover'], "#2471a3" ) CALIBRATION_BUTTON_STYLE = get_button_style( UI_COLORS['btn_orange'], UI_COLORS['btn_orange_hover'], "#d68910" ) BATCH_BUTTON_STYLE = get_button_style( UI_COLORS['btn_purple'], UI_COLORS['btn_purple_hover'], "#7d3c98" ) LOCULE_BUTTON_STYLE = get_button_style( "#16a085", # Teal "#138d75", # Darker teal "#117864" # Even darker teal ) EMERGENCY_BUTTON_STYLE = f""" QPushButton {{ background-color: {UI_COLORS['btn_red']}; border: 2px solid {UI_COLORS['btn_red_hover']}; border-radius: 15px; color: white; font-weight: bold; font-size: 14px; }} QPushButton:hover {{ background-color: {UI_COLORS['btn_red_hover']}; }} """ STANDARD_BUTTON_STYLE = f""" QPushButton {{ background-color: {UI_COLORS['primary_light']}; border: 1px solid {UI_COLORS['primary_dark']}; border-radius: 4px; color: white; padding: 10px; font-size: 16px; }} QPushButton:hover {{ background-color: {UI_COLORS['primary_dark']}; }} """ # ==================== TABLE STYLES ==================== TABLE_STYLE = f""" QTableWidget {{ gridline-color: #ddd; background-color: {UI_COLORS['bg_white']}; alternate-background-color: {UI_COLORS['bg_light']}; font-size: 16px; }} QHeaderView::section {{ background-color: {UI_COLORS['bg_light']}; padding: 8px; border: 1px solid #ddd; font-weight: bold; font-size: 16px; }} """ # ==================== TAB WIDGET STYLES ==================== TAB_WIDGET_STYLE = f""" QTabWidget::pane {{ border: 1px solid {UI_COLORS['primary_light']}; background-color: {UI_COLORS['bg_white']}; }} QTabBar::tab {{ background-color: {UI_COLORS['primary_light']}; color: {UI_COLORS['bg_panel']}; padding: 12px 16px; margin-right: 2px; font-size: 14px; font-weight: bold; min-width: 120px; max-width: 180px; }} QTabBar::tab:selected {{ background-color: {UI_COLORS['accent_blue']}; color: white; }} QTabBar::tab:hover {{ background-color: {UI_COLORS['accent_blue']}; opacity: 0.8; }} QTabBar::left-button, QTabBar::right-button {{ background-color: {UI_COLORS['primary_light']}; border: none; }} """ # ==================== HEADER STYLES ==================== HEADER_STYLE = f""" QFrame {{ background-color: {UI_COLORS['primary_dark']}; }} QLabel {{ color: white; }} """ HEADER_ICON_BUTTON_STYLE = f""" QPushButton {{ background-color: transparent; border: 2px solid transparent; border-radius: 8px; color: white; font-size: 20px; padding: 8px 12px; min-width: 45px; min-height: 45px; }} QPushButton:hover {{ background-color: rgba(255, 255, 255, 0.1); border: 2px solid rgba(255, 255, 255, 0.3); }} QPushButton:pressed {{ background-color: rgba(255, 255, 255, 0.2); }} """ # ==================== STATUS BAR STYLES ==================== STATUS_BAR_STYLE = f""" QFrame {{ background-color: {UI_COLORS['primary_light']}; }} QLabel {{ color: {UI_COLORS['bg_panel']}; font-size: 16px; }} """ # ==================== LABEL STYLES ==================== def get_label_style( color: str = None, font_size: int = 16, font_weight: str = "normal", background: str = None ) -> str: """ Generate a label stylesheet. Args: color: Text color font_size: Font size in pixels font_weight: Font weight (normal, bold) background: Background color Returns: str: Label stylesheet """ styles = [] if color: styles.append(f"color: {color};") if font_size: styles.append(f"font-size: {font_size}px;") if font_weight: styles.append(f"font-weight: {font_weight};") if background: styles.append(f"background-color: {background};") return " ".join(styles) HEADER_LABEL_STYLE = get_label_style( color=UI_COLORS['text_dark'], font_size=16, font_weight="bold" ) INFO_LABEL_STYLE = get_label_style( color=UI_COLORS['text_medium'], font_size=16 ) STATUS_LABEL_STYLE = get_label_style( color=UI_COLORS['text_dark'], font_size=16 ) # ==================== FEED/DISPLAY STYLES ==================== def get_feed_style(bg_color: str, border_color: str) -> str: """ Generate a camera feed display stylesheet. Args: bg_color: Background color border_color: Border color Returns: str: Feed display stylesheet """ return f""" background-color: {bg_color}; border: 1px solid {border_color}; color: white; font-size: 16px; """ RGB_FEED_STYLE = get_feed_style(UI_COLORS['primary_dark'], UI_COLORS['primary_light']) MS_FEED_STYLE = get_feed_style(UI_COLORS['btn_purple'], "#9b59b6") THERMAL_FEED_STYLE = get_feed_style(UI_COLORS['text_medium'], "#95a5a6") AUDIO_FEED_STYLE = get_feed_style("#16a085", "#1abc9c") # ==================== APPLICATION STYLE ==================== APPLICATION_STYLE = """ QApplication { font-family: Arial, sans-serif; } """ # ==================== LOADING OVERLAY STYLE ==================== LOADING_STYLE = """ background-color: rgba(255, 255, 255, 0%); """ # ==================== UTILITY FUNCTIONS ==================== def get_status_indicator_style(status: str) -> str: """ Get the stylesheet for a status indicator. Args: status: Status type ('online', 'offline', 'updating') Returns: str: Stylesheet for the status indicator """ status_colors = { "online": UI_COLORS['online'], "offline": UI_COLORS['offline'], "updating": UI_COLORS['updating'], } color = status_colors.get(status, UI_COLORS['text_medium']) return f"background-color: {color}; border-radius: 6px;" def get_grade_color(grade: str) -> str: """ Get the color for a quality grade. Args: grade: Grade letter ('A', 'B', 'C', etc.) Returns: str: Color hex code """ # Handle None or empty grades if not grade: return UI_COLORS['text_dark'] grade_colors = { "A": UI_COLORS['grade_a'], "B": UI_COLORS['grade_b'], "C": UI_COLORS['grade_c'], } return grade_colors.get(str(grade).upper(), UI_COLORS['text_dark']) def get_ripeness_color(ripeness: str) -> str: """ Get the color for a ripeness classification. Args: ripeness: Ripeness type ('Ripe', 'Overripe', 'Unripe') Returns: str: Color hex code """ ripeness_colors = { "Ripe": UI_COLORS['online'], "Overripe": UI_COLORS['updating'], "Unripe": UI_COLORS['text_medium'], } return ripeness_colors.get(ripeness, UI_COLORS['text_dark'])