import 'package:flutter/material.dart'; import 'package:askiineverdie/src/shared/retro_colors.dart'; /// 레트로 RPG 스타일 버튼 /// 8-bit 게임의 눌림 효과를 재현 class RetroButton extends StatefulWidget { const RetroButton({ super.key, required this.child, this.onPressed, this.isPrimary = true, this.padding = const EdgeInsets.symmetric(horizontal: 16, vertical: 12), }); /// 버튼 내부 컨텐츠 final Widget child; /// 클릭 콜백 (null이면 비활성화) final VoidCallback? onPressed; /// Primary 버튼 여부 (색상 차이) final bool isPrimary; /// 내부 패딩 final EdgeInsets padding; @override State createState() => _RetroButtonState(); } class _RetroButtonState extends State { bool _isPressed = false; bool _isHovered = false; bool get _isEnabled => widget.onPressed != null; Color get _backgroundColor { if (!_isEnabled) return RetroColors.buttonSecondary.withValues(alpha: 0.5); if (_isPressed) { return widget.isPrimary ? RetroColors.buttonPrimaryPressed : RetroColors.buttonSecondaryPressed; } // 호버 시 밝아지는 효과 if (_isHovered) { return widget.isPrimary ? RetroColors.buttonPrimary.withValues(alpha: 0.9) : RetroColors.buttonSecondary.withValues(alpha: 0.9); } return widget.isPrimary ? RetroColors.buttonPrimary : RetroColors.buttonSecondary; } Color get _borderTopLeft { if (_isPressed) return RetroColors.panelBorderOuter; // 호버 시 골드 테두리 if (_isHovered && _isEnabled) return RetroColors.gold; return RetroColors.panelBorderInner; } Color get _borderBottomRight { if (_isPressed) return RetroColors.panelBorderInner; // 호버 시 골드 테두리 if (_isHovered && _isEnabled) return RetroColors.goldDark; return RetroColors.panelBorderOuter; } @override Widget build(BuildContext context) { return MouseRegion( onEnter: _isEnabled ? (_) => setState(() => _isHovered = true) : null, onExit: _isEnabled ? (_) => setState(() => _isHovered = false) : null, cursor: _isEnabled ? SystemMouseCursors.click : SystemMouseCursors.basic, child: GestureDetector( onTapDown: _isEnabled ? (_) => setState(() => _isPressed = true) : null, onTapUp: _isEnabled ? (_) => setState(() => _isPressed = false) : null, onTapCancel: _isEnabled ? () => setState(() => _isPressed = false) : null, onTap: widget.onPressed, child: AnimatedContainer( duration: const Duration(milliseconds: 100), padding: widget.padding, decoration: BoxDecoration( color: _backgroundColor, border: Border( top: BorderSide(color: _borderTopLeft, width: 2), left: BorderSide(color: _borderTopLeft, width: 2), bottom: BorderSide(color: _borderBottomRight, width: 2), right: BorderSide(color: _borderBottomRight, width: 2), ), // 호버 시 글로우 효과 boxShadow: _isHovered && _isEnabled ? [ BoxShadow( color: RetroColors.gold.withValues(alpha: 0.3), blurRadius: 8, spreadRadius: 1, ), ] : null, ), transform: _isPressed ? Matrix4.translationValues(1, 1, 0) : Matrix4.identity(), child: DefaultTextStyle( style: TextStyle( fontFamily: 'PressStart2P', fontSize: 10, color: _isEnabled ? (_isHovered ? RetroColors.gold : RetroColors.textLight) : RetroColors.textDisabled, ), child: widget.child, ), ), ), ); } } /// 레트로 텍스트 버튼 (간편 생성용) class RetroTextButton extends StatelessWidget { const RetroTextButton({ super.key, required this.text, this.onPressed, this.isPrimary = true, this.icon, }); final String text; final VoidCallback? onPressed; final bool isPrimary; final IconData? icon; @override Widget build(BuildContext context) { return RetroButton( onPressed: onPressed, isPrimary: isPrimary, child: Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ if (icon != null) ...[ Icon(icon, size: 14, color: RetroColors.textLight), const SizedBox(width: 8), ], Text(text.toUpperCase()), ], ), ); } } /// 레트로 아이콘 버튼 class RetroIconButton extends StatelessWidget { const RetroIconButton({ super.key, required this.icon, this.onPressed, this.size = 32, }); final IconData icon; final VoidCallback? onPressed; final double size; @override Widget build(BuildContext context) { return RetroButton( onPressed: onPressed, padding: EdgeInsets.all(size * 0.25), child: Icon(icon, size: size * 0.5, color: RetroColors.textLight), ); } } /// 레트로 호버 효과 리스트 아이템 /// 웹/데스크톱에서 마우스 호버 시 하이라이트 효과 class RetroHoverItem extends StatefulWidget { const RetroHoverItem({ super.key, required this.child, this.onTap, this.isSelected = false, this.padding = const EdgeInsets.symmetric(horizontal: 8, vertical: 4), }); final Widget child; final VoidCallback? onTap; final bool isSelected; final EdgeInsets padding; @override State createState() => _RetroHoverItemState(); } class _RetroHoverItemState extends State { bool _isHovered = false; @override Widget build(BuildContext context) { final isHighlighted = _isHovered || widget.isSelected; return MouseRegion( onEnter: (_) => setState(() => _isHovered = true), onExit: (_) => setState(() => _isHovered = false), cursor: widget.onTap != null ? SystemMouseCursors.click : SystemMouseCursors.basic, child: GestureDetector( onTap: widget.onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 100), padding: widget.padding, decoration: BoxDecoration( color: isHighlighted ? RetroColors.panelBgLight.withValues(alpha: 0.5) : Colors.transparent, border: isHighlighted ? Border( left: BorderSide( color: widget.isSelected ? RetroColors.gold : RetroColors.gold.withValues(alpha: 0.5), width: 2, ), ) : null, ), child: widget.child, ), ), ); } } /// 레트로 호버 패널 /// 웹/데스크톱에서 패널 호버 시 미세 확대 및 글로우 효과 class RetroHoverPanel extends StatefulWidget { const RetroHoverPanel({ super.key, required this.child, this.onTap, this.enableScale = true, }); final Widget child; final VoidCallback? onTap; final bool enableScale; @override State createState() => _RetroHoverPanelState(); } class _RetroHoverPanelState extends State { bool _isHovered = false; @override Widget build(BuildContext context) { return MouseRegion( onEnter: (_) => setState(() => _isHovered = true), onExit: (_) => setState(() => _isHovered = false), cursor: widget.onTap != null ? SystemMouseCursors.click : SystemMouseCursors.basic, child: GestureDetector( onTap: widget.onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 150), transform: widget.enableScale && _isHovered ? Matrix4.diagonal3Values(1.01, 1.01, 1.0) : Matrix4.identity(), transformAlignment: Alignment.center, decoration: BoxDecoration( boxShadow: _isHovered ? [ BoxShadow( color: RetroColors.gold.withValues(alpha: 0.2), blurRadius: 12, spreadRadius: 2, ), ] : null, ), child: widget.child, ), ), ); } }