diff --git a/.gitignore b/.gitignore index 7d4eba5ff27b8d8722c1fba3c21431d6879aa61c..38d476155dd65a39ea39e5902295faf299c344a5 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,6 @@ bandit_project_report.html 文档/过度防御性设计报告.md 文档/收藏数据延迟加载优化方案.md /配色方案 +明度分析.py +明度分析_GUI.py +/demos diff --git a/README.md b/README.md index c62e225c7c020c38a3d1afb39f40e59c0b8008cf..df1919ee2e1670b59b38598c7ce04ea619075686 100644 --- a/README.md +++ b/README.md @@ -38,20 +38,20 @@ | 指标 | 数据 | | :---- | :---------------------- | -| 发布版本 | 11 个版本(v1.0.0 → v1.7.1) | -| 开发周期 | 66 天 | -| 总更新项 | **133 项** | +| 发布版本 | 12 个版本(v1.0.0 → v1.8.0) | +| 开发周期 | 73 天 | +| 总更新项 | **145 项** | | 平均每版本 | 12.1 项 | **详细分类统计**: | 分类 | 数量 | 说明 | | :------- | :----: | :-------------- | -| ✨ 新增功能 | **36** | 包含首次发布的 9 项核心功能 | -| 🔧 问题修复 | **32** | 持续修复 Bug,提升稳定性 | -| 🎨 界面优化 | **35** | 用户体验打磨 | +| ✨ 新增功能 | **39** | 包含首次发布的 9 项核心功能 | +| 🔧 问题修复 | **34** | 持续修复 Bug,提升稳定性 | +| 🎨 界面优化 | **39** | 用户体验打磨 | | ⚡ 性能提升 | **11** | 缓存机制、启动优化等 | -| 📝 内容调整 | **5** | 文本、名称等调整 | +| 📝 内容调整 | **7** | 文本、名称等调整 | | ⚙️ 体验优化 | **5** | 交互体验改进 | | 🏗️ 代码优化 | **2** | 代码结构优化 | | 🔮 逻辑优化 | **2** | 算法逻辑改进 | @@ -67,7 +67,7 @@ |------|---------| | **色彩信息提取**
通过可拖动取色点实时提取图片颜色,支持多色彩空间显示(HSB、LAB、HSL、CMYK、RGB) | ![色彩提取](docs/screenshots/color-extract.png) | | **明度分析**
将图片按明度分为9个区域(基于Adobe标准),提供直方图可视化,可快速分析图片影调 | ![明度分析](docs/screenshots/luminance-extract.png) | -| **渐变色提取**
通过起始色和结束色生成渐变色序列,支持 RGB/HSB/LAB 三种颜色空间插值 | ![渐变色提取](docs/screenshots/Gradient%20Extract.png) | +| **渐变色提取**
支持双色渐变和单色明度梯度两种模式,双色渐变通过起始色和结束色生成渐变色序列,单色明度梯度固定色相饱和度按明度分级生成色阶(类似 Tailwind 50-900),支持 RGB/HSB/HSL/LAB 四种颜色空间插值 | ![渐变色提取](docs/screenshots/Gradient%20Extract.png) | | **配色生成**
提供5种专业配色方案(同色系、邻近色、互补色、分离补色、双补色),支持可交互色环选择 | ![配色生成](docs/screenshots/color-generation.png) | | **配色收藏**
支持收藏、管理配色方案,支持批量导入导出为JSON文件,支持单组色卡导出为 Adobe ASE 格式 | ![配色管理](docs/screenshots/palette-management.png) | | **内置色彩库**
集成 Open Color、Tailwind CSS、Material Design 等13大开源配色方案,总计661组色卡 | ![内置色彩库](docs/screenshots/preset-colors.png) | @@ -162,7 +162,7 @@ | :---- | :------------------------------------------------ | | 色彩提取 | 可拖动取色点、多色彩空间显示、一键复制颜色值 | | 明度分析 | 9级明度分区(Zone 0-8)、直方图可视化、区域高亮 | -| 渐变色提取 | 起始色/结束色设置、RGB/HSB/LAB插值、中间色数量调节 | +| 渐变色提取 | 双色渐变/单色明度梯度两种模式、RGB/HSB/HSL/LAB插值、中间色数量调节 | | | 配色生成 | 5种配色方案、可交互色环、明度调整 | | 配色管理 | 收藏配色、自定义名称、批量导入导出为JSON文件、支持单组配色ASE格式导出(支持Adobe软件) | | 配色预览 | 8种内置场景、自定义SVG、智能配色映射 | @@ -289,20 +289,20 @@ Since the release of v1.0.0 on 2026-02-05, the project has maintained a fast and | Metric | Data | | :------------------ | :---------------------------- | -| Released Versions | 11 versions (v1.0.0 → v1.7.1) | -| Development Period | 66 days | -| Total Updates | **133 items** | +| Released Versions | 12 versions (v1.0.0 → v1.8.0) | +| Development Period | 73 days | +| Total Updates | **145 items** | | Average per Version | 12.1 items | **Detailed Category Statistics(portion)**: | Category | Count | Description | | :--------------------- | :----: | :------------------------------------------- | -| ✨ New Features | **36** | Including 9 core features from v1.0.0 launch | -| 🔧 Bug Fixes | **32** | Continuous bug fixes for stability | -| 🎨 UI Improvements | **35** | User experience refinements | +| ✨ New Features | **39** | Including 9 core features from v1.0.0 launch | +| 🔧 Bug Fixes | **34** | Continuous bug fixes for stability | +| 🎨 UI Improvements | **39** | User experience refinements | | ⚡ Performance | **11** | Cache mechanism, startup optimization | -| 📝 Content Adjustments | **5** | Text, naming adjustments | +| 📝 Content Adjustments | **7** | Text, naming adjustments | | ⚙️ Experience | **5** | Interaction improvements | | 🏗️ Code Optimization | **2** | Code structure optimization | | 🔮 Logic Optimization | **2** | Algorithm improvements | @@ -318,7 +318,7 @@ Since the release of v1.0.0 on 2026-02-05, the project has maintained a fast and |---------|------------| | **Visual Color Extraction**
Real-time color extraction via draggable color pickers, supporting multiple color spaces (HSB, LAB, HSL, CMYK, RGB) | ![Color Extraction](docs/screenshots/color-extract.png) | | **Luminance Analysis**
9-zone luminance segmentation (Zone 0-8 based on Adobe standard) with histogram visualization | ![Luminance Analysis](docs/screenshots/luminance-extract.png) | -| **Gradient Extraction**
Generate gradient color sequences from start and end colors, supporting RGB/HSB/LAB color space interpolation | ![Gradient Extraction](docs/screenshots/Gradient%20Extract.png) | +| **Gradient Extraction**
Two modes: two-color gradient generates sequences from start/end colors, lightness shades generates scales by brightness with fixed hue/saturation (like Tailwind 50-900), supporting RGB/HSB/HSL/LAB color space interpolation | ![Gradient Extraction](docs/screenshots/Gradient%20Extract.png) | | **Color Scheme Generation**
5 professional color schemes (Monochromatic, Analogous, Complementary, Split-Complementary, Double Complementary) with interactive color wheel | ![Color Generation](docs/screenshots/color-generation.png) | | **Palette Collection**
Save and manage color schemes, support batch import/export in JSON format, support single palette export to Adobe ASE format | ![Palette Management](docs/screenshots/palette-management.png) | | **Built-in Color Library**
13 major open-source color schemes including Open Color, Tailwind CSS, Material Design, totaling 661 color palettes | ![Preset Colors](docs/screenshots/preset-colors.png) | @@ -411,7 +411,7 @@ Since the release of v1.0.0 on 2026-02-05, the project has maintained a fast and | Module | Features | | :------------------ | :------------------------------------------------------------------------------------------------------------------------------------ | | Color Extraction | Draggable pickers, multiple color spaces, one-click copy | -| Gradient Extraction | Start/end color selection, RGB/HSB/LAB interpolation, adjustable middle colors | +| Gradient Extraction | Two-color gradient / lightness shades modes, RGB/HSB/HSL/LAB interpolation, adjustable middle colors | | | Luminance Analysis | 9-zone segmentation (Zone 0-8), histogram visualization, zone highlighting | | Color Generation | 5 color schemes, interactive color wheel, luminance adjustment | | Palette Management | Save palettes, custom names, batch import/export in JSON format, support single palette ASE format export (Adobe software compatible) | diff --git a/core/__init__.py b/core/__init__.py index 238bfb3196a4508de46543a8da9e35edce52254c..1aeb440e1c5b623eb2b5e88981bae92a0861ba2e 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,7 +1,7 @@ """核心功能模块""" # 启动必需的模块立即导入 -from .config import ConfigManager, get_config_manager, SceneConfigManager, get_scene_config_manager, SceneTypeManager, get_scene_type_manager, ConfigLoadError +from .config import ConfigManager, get_config_manager, SceneConfigManager, get_scene_config_manager, SceneTypeManager, get_scene_type_manager from .app_mode import ( AppMode, @@ -74,6 +74,8 @@ from .color_data import ( from .gradient import ( generate_gradient, generate_random_gradient, + generate_lightness_shades, + generate_random_lightness_shade, ) from .async_loader import BaseBatchLoader @@ -122,6 +124,8 @@ __all__ = [ # 颜色工具函数 'generate_gradient', 'generate_random_gradient', + 'generate_lightness_shades', + 'generate_random_lightness_shade', 'rgb_to_hsb', 'rgb_to_lab', 'rgb_to_hex', @@ -163,7 +167,6 @@ __all__ = [ 'get_scene_config_manager', 'SceneTypeManager', 'get_scene_type_manager', - 'ConfigLoadError', # 应用模式 'AppMode', 'Platform', diff --git a/core/color.py b/core/color.py index 62fc415069d20360d4633632df456fc400c22f80..c3e3b8d3a151b26d56f654c906a74ee9249145ae 100644 --- a/core/color.py +++ b/core/color.py @@ -329,7 +329,11 @@ def get_zone_bounds(zone_str: str) -> Tuple[int, int]: tuple: (min_luminance, max_luminance) 元组 """ start = int(zone_str.split('-')[0]) - return (int(start * ZONE_WIDTH), int((start + 1) * ZONE_WIDTH) - 1) + min_lum = int(start * ZONE_WIDTH) + max_lum = int((start + 1) * ZONE_WIDTH) + if max_lum < 255: + max_lum -= 1 + return (min_lum, max_lum) def calculate_histogram(image, sample_step: int = 4, gamma: float = 2.2) -> List[int]: diff --git a/core/config.py b/core/config.py index cc649cbf761d627162e5c97464e3c8e795cb1ba0..4bc447618a37b95c29d5d31bb687b72b891688ae 100644 --- a/core/config.py +++ b/core/config.py @@ -33,11 +33,6 @@ def get_base_path() -> str: logger = get_logger("config") -class ConfigLoadError(Exception): - """配置文件加载错误""" - pass - - class ConfigManager: """配置管理器,处理应用程序配置的加载和保存""" @@ -76,10 +71,12 @@ class ConfigManager: "color_sample_count": 5, "luminance_sample_count": 5, "histogram_scaling_mode": "adaptive", + "luminance_histogram_style": "line", "color_wheel_mode": "RGB", "theme": "auto", "color_wheel_labels_visible": True, - "language": "auto" + "language": "auto", + "gradient_mode": "gradient" }, "scheme": { "default_scheme": "monochromatic", @@ -115,11 +112,25 @@ class ConfigManager: logger.info(f"配置加载完成: version={version}") except (json.JSONDecodeError, IOError, OSError) as e: - logger.error(f"加载配置文件失败: error={e}") - raise ConfigLoadError(f"无法加载配置文件: {e}") from e + logger.error(f"加载配置文件失败,使用默认配置: error={e}") + # 备份损坏的配置文件(如果存在) + self._backup_corrupted_config() return self._config + def _backup_corrupted_config(self) -> None: + """备份损坏的配置文件""" + if not self._config_path.exists(): + return + try: + backup_path = self._config_path.with_suffix( + f'.corrupted.{datetime.now().strftime("%Y%m%d_%H%M%S")}.json' + ) + self._config_path.rename(backup_path) + logger.info(f"已备份损坏的配置文件: {backup_path.name}") + except (IOError, OSError) as e: + logger.warning(f"备份损坏配置文件失败: {e}") + def _merge_config(self, base: Dict[str, Any], override: Dict[str, Any]) -> None: """递归合并配置字典 diff --git a/core/gradient.py b/core/gradient.py index 3f663c786645c67207a3727b62f87d303df47c5e..00ddfa83d3dfa3c1ad12de4048d03967536b50c3 100644 --- a/core/gradient.py +++ b/core/gradient.py @@ -2,7 +2,7 @@ from typing import List, Tuple # 项目模块导入 -from .color import hex_to_rgb, rgb_to_hsb, rgb_to_lab, hsb_to_rgb +from .color import hex_to_rgb, rgb_to_hsb, rgb_to_lab, hsb_to_rgb, rgb_to_hsl, hsl_to_rgb def _normalize_hue_for_interpolation(h1: float, h2: float) -> Tuple[float, float]: @@ -87,6 +87,37 @@ def _interpolate_hsb(start_rgb: Tuple[int, int, int], end_rgb: Tuple[int, int, i return colors +def _interpolate_hsl(start_rgb: Tuple[int, int, int], end_rgb: Tuple[int, int, int], steps: int) -> List[Tuple[int, int, int]]: + """在HSL空间进行插值,色相沿最短路径过渡 + + Args: + start_rgb: 起始RGB颜色 (r, g, b) + end_rgb: 结束RGB颜色 (r, g, b) + steps: 中间色数量 + + Returns: + List[Tuple[int, int, int]]: RGB颜色列表,包含起始色、中间色、结束色 + """ + h1, s1, l1 = rgb_to_hsl(*start_rgb) + h2, s2, l2 = rgb_to_hsl(*end_rgb) + + h1, h2 = _normalize_hue_for_interpolation(h1, h2) + + colors = [start_rgb] + total_segments = steps + 1 + + for i in range(1, steps + 1): + t = i / total_segments + h = h1 + (h2 - h1) * t + s = s1 + (s2 - s1) * t + l = l1 + (l2 - l1) * t + h = h % 360 + colors.append(hsl_to_rgb(h, s, l)) + + colors.append(end_rgb) + return colors + + def _interpolate_lab(start_rgb: Tuple[int, int, int], end_rgb: Tuple[int, int, int], steps: int) -> List[Tuple[int, int, int]]: """在LAB空间进行线性插值 @@ -180,13 +211,13 @@ def generate_gradient( ) -> List[Tuple[int, int, int]]: """生成渐变色序列 - 支持RGB、HSB、LAB三种颜色空间的插值 + 支持RGB、HSB、HSL、LAB四种颜色空间的插值 Args: start_hex: 起始颜色HEX值,如"#FF0000" end_hex: 结束颜色HEX值,如"#0000FF" steps: 中间色数量 (1-10) - color_space: 颜色空间 ('rgb', 'hsb', 'lab'),默认'lab' + color_space: 颜色空间 ('rgb', 'hsb', 'hsl', 'lab'),默认'lab' Returns: List[Tuple[int, int, int]]: RGB颜色列表,包含起始色、所有中间色、结束色 @@ -194,22 +225,20 @@ def generate_gradient( Raises: ValueError: 当输入的HEX值格式无效时 """ - # 解析HEX值 start_rgb = hex_to_rgb(start_hex) end_rgb = hex_to_rgb(end_hex) - # 确保steps在有效范围内 steps = max(1, min(10, steps)) - # 根据颜色空间选择插值方法 if color_space == 'rgb': return _interpolate_rgb(start_rgb, end_rgb, steps) elif color_space == 'hsb': return _interpolate_hsb(start_rgb, end_rgb, steps) + elif color_space == 'hsl': + return _interpolate_hsl(start_rgb, end_rgb, steps) elif color_space == 'lab': return _interpolate_lab(start_rgb, end_rgb, steps) else: - # 默认使用LAB空间 return _interpolate_lab(start_rgb, end_rgb, steps) @@ -218,7 +247,7 @@ def generate_random_gradient(steps: int = 2, color_space: str = 'lab') -> Tuple[ Args: steps: 中间色数量 (1-10),默认2 - color_space: 颜色空间 ('rgb', 'hsb', 'lab'),默认'lab' + color_space: 颜色空间 ('rgb', 'hsb', 'hsl', 'lab'),默认'lab' Returns: Tuple[str, str, List[Tuple[int, int, int]]]: (起始色HEX, 结束色HEX, RGB颜色列表) @@ -238,3 +267,80 @@ def generate_random_gradient(steps: int = 2, color_space: str = 'lab') -> Tuple[ colors = generate_gradient(start_hex, end_hex, steps, color_space) return start_hex, end_hex, colors + + +def generate_lightness_shades( + base_hex: str, + count: int = 9, + color_space: str = 'hsb' +) -> List[Tuple[int, int, int]]: + """生成单色明度梯度 + + 固定色相和饱和度,明度从高到低均匀分布 + 支持HSB、HSL、LAB三种颜色空间 + + Args: + base_hex: 基准颜色HEX值,如"#FF5733" + count: 色阶数量 (3-13),默认9 + color_space: 颜色空间 ('hsb', 'hsl', 'lab'),默认'hsb' + + Returns: + List[Tuple[int, int, int]]: RGB颜色列表 + + Raises: + ValueError: 当输入的HEX值格式无效时 + """ + count = max(3, min(13, count)) + + base_rgb = hex_to_rgb(base_hex) + + min_lightness = 10 + max_lightness = 95 + step = (max_lightness - min_lightness) / (count - 1) + + colors = [] + + if color_space == 'lab': + # LAB空间:固定a/b,L从95到10均匀分布 + L, A, B = rgb_to_lab(*base_rgb) + for i in range(count): + lightness = max_lightness - i * step + colors.append(_lab_to_rgb(lightness, A, B)) + elif color_space == 'hsl': + # HSL空间:固定H/S,L从95%到10%均匀分布 + H, S, _ = rgb_to_hsl(*base_rgb) + for i in range(count): + lightness = max_lightness - i * step + colors.append(hsl_to_rgb(H, S, lightness)) + else: + # HSB空间(默认):固定H/S,B从95到10均匀分布 + H, S, _ = rgb_to_hsb(*base_rgb) + for i in range(count): + B = max_lightness - i * step + colors.append(hsb_to_rgb(H, S, B)) + + return colors + + +def generate_random_lightness_shade( + count: int = 9, + color_space: str = 'hsb' +) -> Tuple[str, List[Tuple[int, int, int]]]: + """生成随机单色明度梯度 + + Args: + count: 色阶数量 (3-13),默认9 + color_space: 颜色空间 ('hsb', 'hsl', 'lab'),默认'hsb' + + Returns: + Tuple[str, List[Tuple[int, int, int]]]: (基准色HEX, RGB颜色列表) + """ + import random + from .color import rgb_to_hex + + base_rgb = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) + base_hex = rgb_to_hex(*base_rgb) + + colors = generate_lightness_shades(base_hex, count, color_space) + + return base_hex, colors diff --git a/core/luminance_service.py b/core/luminance_service.py index 12549e030963b2086fb7309b0ea7a0491e04b997..667d8d65b0fd2fcefdac445b0d1fcf525a523a78 100644 --- a/core/luminance_service.py +++ b/core/luminance_service.py @@ -12,7 +12,7 @@ from PySide6.QtCore import QObject, QThread, Signal, Qt, QTimer from PySide6.QtGui import QColor, QImage, QPainter, QPixmap # 项目模块导入 -from .color import get_luminance, get_zone, ZONE_WIDTH +from .color import get_luminance, get_zone, get_zone_bounds from .logger import get_logger, log_performance logger = get_logger("luminance_service") @@ -351,8 +351,7 @@ class LuminanceService(QObject): painter = QPainter(highlight_pixmap) painter.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform) - min_lum = int(zone * ZONE_WIDTH) - max_lum = int((zone + 1) * ZONE_WIDTH) - 1 + min_lum, max_lum = get_zone_bounds(f"{zone}-{zone+1}") scale_x = image.width() / disp_w scale_y = image.height() / disp_h diff --git a/docs/changelog.json b/docs/changelog.json index a5c281f9b1a21a42fa7d3038aeaf7ad1913497e1..2b1b94b2c95681d8f7c5af6c82485d885d15d2ad 100644 --- a/docs/changelog.json +++ b/docs/changelog.json @@ -1,5 +1,51 @@ { "versions": [ + { + "version": "v1.8.0", + "date": "2026-04-19", + "changes": [ + { + "category": "新增功能", + "items": [ + { + "title": "渐变提取增强", + "desc": "新增单色明度梯度模式,渐变提取支持HSL颜色空间插值" + }, + { + "title": "主题系统", + "desc": "主题切换按钮增加跟随系统状态" + }, + { + "title": "明度直方图", + "desc": "支持线连接和柱状图两种样式切换" + } + ] + }, + { + "category": "问题修复", + "items": [ + "修正明度区域8-9明度遮罩未覆盖纯白色像素的问题", + "配置文件加载失败时使用默认配置" + ] + }, + { + "category": "界面优化", + "items": [ + "统一明度提取和色彩提取面板的提示文字字体样式", + "调整渐变提取界面颜色圆点样式", + "统一场景SVG尺寸、文字颜色并优化元素属性、布局", + "修复部分系统配色预览区域间隔显示灰条问题" + ] + }, + { + "category": "内容调整", + "items": [ + "新增大量SVG场景", + "启用配色预览混合布局并设为默认" + ] + } + ] + }, { "version": "v1.7.1", "date": "2026-04-12", diff --git a/docs/index.html b/docs/index.html index fe114e56c693a16b6660b45566d53179d3c27819..0c2f547043294611fc2b426e2ba96d7b21943282 100644 --- a/docs/index.html +++ b/docs/index.html @@ -618,7 +618,7 @@ 渐变生成

渐变生成

-

生成渐变色序列,支持多种颜色空间

+

双色渐变与单色明度梯度,支持多种颜色空间

@@ -1261,7 +1261,7 @@ { icon: 'library', title: '内置色彩库', desc: '集成 Open Color、Tailwind CSS、Material Design 等13大开源配色方案,总计661组色卡' }, { icon: 'eye', title: '配色预览', desc: '支持手机UI、网页、插画、排版、品牌、海报、图案、杂志等8种场景预览,支持自定义SVG' }, { icon: 'barchart', title: '明度分析', desc: '将图片按明度分为9个区域,提供直方图可视化,辅助调色决策' }, - { icon: 'gradient', title: '渐变生成', desc: '选择起始和结束颜色,生成渐变色序列,支持RGB/HSB/LAB三种颜色空间插值,可调节1-10个中间色' }, + { icon: 'gradient', title: '渐变生成', desc: '支持双色渐变和单色明度梯度两种模式,RGB/HSB/HSL/LAB四种颜色空间插值,可调节中间色数量' }, { icon: 'globe', title: '多语言支持', desc: '支持简体中文、繁体中文、英语、日语、法语、俄语六种语言界面切换,支持跟随系统语言自动切换' }, { icon: 'moon', title: '明暗主题', desc: '支持深色模式和浅色模式切换,保护视力,适应不同使用环境' }, ]; diff --git a/locales/FR_FR.toml b/locales/FR_FR.toml index bb22fe5149f3030655ce7acc6878ead413a2415e..f9e21881b5ad3f3161b8c948433ae8350573569d 100644 --- a/locales/FR_FR.toml +++ b/locales/FR_FR.toml @@ -14,8 +14,11 @@ color_preview = "Aperçu des couleurs" settings = "Paramètres" [title_bar] -toggle_theme = "Basculer mode sombre/clair" +toggle_theme = "Changer de thème" toggle_fullscreen = "Plein écran/Quitter plein écran (F11)" +theme_light = "Mode clair" +theme_dark = "Mode sombre" +theme_auto = "Suivre le système" [color_extract] favorite = "Enregistrer" @@ -33,7 +36,9 @@ image_filter = "Fichiers image (*.png *.jpg *.jpeg *.bmp *.gif)" [gradient_extract] start_color = "Couleur de départ" end_color = "Couleur de fin" +base_color = "Couleur de base" steps = "Couleurs intermédiaires" +shade_count = "Nombre de nuances" random = "Aléatoire" favorite = "Enregistrer" select_color = "Sélectionner la couleur" @@ -92,7 +97,7 @@ no_selection = "Veuillez d'abord sélectionner des palettes à supprimer" [color_preview] title = "Aperçu des couleurs" -subtitle = "En cours de développement" +subtitle = "L'importation des mises en page mixtes présente des problèmes, ce module est encore en développement" import_btn = "Importer" export_btn = "Exporter" delete = "Supprimer" @@ -218,6 +223,10 @@ luminance_sample_count_desc = "Définir le nombre de points d'échantillonnage p histogram = "Paramètres de l'histogramme" histogram_scaling = "Mode de mise à l'échelle" histogram_scaling_desc = "Sélectionner la méthode de mise à l'échelle de l'histogramme (Linéaire/Adaptatif)" +luminance_histogram_style = "Style d'histogramme de luminance" +luminance_histogram_style_desc = "Sélectionner le style d'affichage de l'histogramme de luminance" +luminance_histogram_line = "Ligne" +luminance_histogram_bar = "Barres" histogram_mode = "Mode d'affichage de l'histogramme" histogram_mode_desc = "Sélectionner le type d'histogramme pour le panneau d'extraction (Canaux RVB/Distribution teinte)" highlight = "Paramètres de surbrillance" @@ -236,7 +245,12 @@ gradient_color_space = "Espace colorimétrique du dégradé" gradient_color_space_desc = "Sélectionner l'espace colorimétrique pour l'interpolation du dégradé" gradient_rgb = "Espace RGB" gradient_hsb = "Espace HSB" +gradient_hsl = "Espace HSL" gradient_lab = "Espace LAB" +gradient_mode = "Mode de dégradé" +gradient_mode_desc = "Sélectionner le mode d'extraction du dégradé" +gradient_mode_gradient = "Dégradé bicolore" +gradient_mode_shade = "Dégradé monochrome" language = "Paramètres de langue" language_title = "Langue de l'interface" language_desc = "Sélectionner la langue d'affichage de l'application" diff --git a/locales/JA_JP.toml b/locales/JA_JP.toml index 627e9d22591adc0ef232ecd7cf363b11c5c96200..8a06d1c471686fd556d873bdaaab173c61ff75cd 100644 --- a/locales/JA_JP.toml +++ b/locales/JA_JP.toml @@ -14,8 +14,11 @@ color_preview = "カラープレビュー" settings = "設定" [title_bar] -toggle_theme = "ダーク/ライトモード切替" +toggle_theme = "テーマ切替" toggle_fullscreen = "全画面/全画面解除 (F11)" +theme_light = "ライトモード" +theme_dark = "ダークモード" +theme_auto = "システムに従う" [color_extract] favorite = "パレットを保存" @@ -33,7 +36,9 @@ image_filter = "画像ファイル (*.png *.jpg *.jpeg *.bmp *.gif)" [gradient_extract] start_color = "開始色" end_color = "終了色" +base_color = "ベース色" steps = "中間色数" +shade_count = "色階数" random = "ランダム" favorite = "保存" select_color = "色を選択" @@ -92,7 +97,7 @@ no_selection = "削除するパレットを選択してください" [color_preview] title = "カラープレビュー" -subtitle = "開発中です" +subtitle = "混合レイアウトのインポートには問題があります、このモジュールはまだ開発中です" import_btn = "インポート" export_btn = "エクスポート" delete = "削除" @@ -218,6 +223,10 @@ luminance_sample_count_desc = "輝度抽出パネルのサンプルポイント histogram = "ヒストグラム設定" histogram_scaling = "ヒストグラムスケーリングモード" histogram_scaling_desc = "ヒストグラムのスケーリング方法を選択(線形/アダプティブ)" +luminance_histogram_style = "輝度ヒストグラムスタイル" +luminance_histogram_style_desc = "輝度ヒストグラムの表示スタイルを選択" +luminance_histogram_line = "線接続" +luminance_histogram_bar = "棒グラフ" histogram_mode = "ヒストグラム表示モード" histogram_mode_desc = "カラー抽出パネルのヒストグラムタイプを選択(RGBチャンネル/色相分布)" highlight = "ハイライト領域設定" @@ -236,7 +245,12 @@ gradient_color_space = "グラデーション色空間" gradient_color_space_desc = "グラデーション補間に使用する色空間を選択" gradient_rgb = "RGB 空間" gradient_hsb = "HSB 空間" +gradient_hsl = "HSL 空間" gradient_lab = "LAB 空間" +gradient_mode = "グラデーションモード" +gradient_mode_desc = "グラデーション抽出のモードを選択" +gradient_mode_gradient = "二色グラデーション" +gradient_mode_shade = "単色グラデーション" language = "言語設定" language_title = "インターフェース言語" language_desc = "アプリケーションの表示言語を選択" diff --git a/locales/RU_RU.toml b/locales/RU_RU.toml index 94ceeb0e3a84ed892e23f865be1b447f8ae0546a..1ca1506e3947d5f4e8728dee44d13d6b68899f00 100644 --- a/locales/RU_RU.toml +++ b/locales/RU_RU.toml @@ -14,8 +14,11 @@ color_preview = "Предпросмотр цвета" settings = "Настройки" [title_bar] -toggle_theme = "Переключить темную/светлую тему" +toggle_theme = "Переключить тему" toggle_fullscreen = "Полноэкранный режим/Выход (F11)" +theme_light = "Светлая тема" +theme_dark = "Темная тема" +theme_auto = "Как в системе" [color_extract] favorite = "Сохранить" @@ -33,7 +36,9 @@ image_filter = "Файлы изображений (*.png *.jpg *.jpeg *.bmp *.gi [gradient_extract] start_color = "Начальный цвет" end_color = "Конечный цвет" +base_color = "Базовый цвет" steps = "Промежуточные цвета" +shade_count = "Количество оттенков" random = "Случайный" favorite = "Сохр." select_color = "Выбрать цвет" @@ -93,7 +98,7 @@ no_selection = "Пожалуйста, сначала выберите палит [color_preview] title = "Предпросмотр цвета" -subtitle = "В разработке" +subtitle = "Импорт смешанных макетов имеет некоторые проблемы, модуль всё ещё в разработке" import_btn = "Импорт" export_btn = "Экспорт" delete = "Удалить" @@ -219,6 +224,10 @@ luminance_sample_count_desc = "Установите количество точ histogram = "Настройки гистограммы" histogram_scaling = "Режим масштабирования" histogram_scaling_desc = "Выберите метод масштабирования гистограммы (Линейный/Адаптивный)" +luminance_histogram_style = "Стиль гистограммы яркости" +luminance_histogram_style_desc = "Выберите стиль отображения гистограммы яркости" +luminance_histogram_line = "Линия" +luminance_histogram_bar = "Столбцы" histogram_mode = "Режим отображения гистограммы" histogram_mode_desc = "Выберите тип гистограммы для панели извлечения (RGB каналы/Распределение оттенков)" highlight = "Настройки выделения" @@ -237,7 +246,12 @@ gradient_color_space = "Цветовое пространство градиен gradient_color_space_desc = "Выберите цветовое пространство для интерполяции градиента" gradient_rgb = "RGB пространство" gradient_hsb = "HSB пространство" +gradient_hsl = "HSL пространство" gradient_lab = "LAB пространство" +gradient_mode = "Режим градиента" +gradient_mode_desc = "Выберите режим извлечения градиента" +gradient_mode_gradient = "Двухцветный градиент" +gradient_mode_shade = "Монохромный градиент" language = "Настройки языка" language_title = "Язык интерфейса" language_desc = "Выберите язык отображения приложения" diff --git a/locales/ZW_FT.toml b/locales/ZW_FT.toml index a41d7a68baef76fe6a0f2dc2d0e2c98a4177ae3a..369420cd27c68337244e3562041a8a73d054f85d 100644 --- a/locales/ZW_FT.toml +++ b/locales/ZW_FT.toml @@ -14,8 +14,11 @@ color_preview = "配色預覽" settings = "設置" [title_bar] -toggle_theme = "切換深色/淺色模式" +toggle_theme = "切換主題" toggle_fullscreen = "全屏/退出全屏 (F11)" +theme_light = "淺色模式" +theme_dark = "深色模式" +theme_auto = "跟隨系統" [color_extract] favorite = "收藏當前配色" @@ -33,7 +36,9 @@ image_filter = "圖片文件 (*.png *.jpg *.jpeg *.bmp *.gif)" [gradient_extract] start_color = "起始顏色" end_color = "結束顏色" +base_color = "基準顏色" steps = "中間色數量" +shade_count = "色階數量" random = "隨機" favorite = "收藏" select_color = "選擇顏色" @@ -92,7 +97,7 @@ no_selection = "請先選擇要刪除的配色" [color_preview] title = "配色預覽" -subtitle = "還在持續完善中" +subtitle = "混合布局的導入存在一定的問題,本模塊還在持續完善中" import_btn = "導入" export_btn = "導出" delete = "刪除" @@ -218,6 +223,10 @@ luminance_sample_count_desc = "設置明度提取面板的取樣點數量(2-8 histogram = "直方圖設置" histogram_scaling = "直方圖縮放模式" histogram_scaling_desc = "選擇直方圖的縮放方式(線性/自適應)" +luminance_histogram_style = "明度直方圖樣式" +luminance_histogram_style_desc = "選擇明度直方圖的顯示樣式" +luminance_histogram_line = "線連接" +luminance_histogram_bar = "柱狀圖" histogram_mode = "直方圖顯示模式" histogram_mode_desc = "選擇色彩提取面板的直方圖類型(RGB通道/色相分布)" highlight = "區域高亮設置" @@ -236,7 +245,12 @@ gradient_color_space = "漸變顏色空間" gradient_color_space_desc = "選擇漸變色插值的顏色空間" gradient_rgb = "RGB 空間" gradient_hsb = "HSB 空間" +gradient_hsl = "HSL 空間" gradient_lab = "LAB 空間" +gradient_mode = "漸變模式" +gradient_mode_desc = "選擇漸變提取的模式" +gradient_mode_gradient = "雙色漸變" +gradient_mode_shade = "單色漸變" language = "語言設置" language_title = "頁面語言" language_desc = "選擇應用程序的顯示語言" diff --git a/locales/ZW_JT.toml b/locales/ZW_JT.toml index 53d3424baa8ba91096a0f6934ce6dd3d98de294e..b2b5f3b054453688ee92e8075994203d67d437af 100644 --- a/locales/ZW_JT.toml +++ b/locales/ZW_JT.toml @@ -14,8 +14,11 @@ color_preview = "配色预览" settings = "设置" [title_bar] -toggle_theme = "切换深色/浅色模式" +toggle_theme = "切换主题" toggle_fullscreen = "全屏/退出全屏 (F11)" +theme_light = "浅色模式" +theme_dark = "深色模式" +theme_auto = "跟随系统" [color_extract] favorite = "收藏当前配色" @@ -33,7 +36,9 @@ image_filter = "图片文件 (*.png *.jpg *.jpeg *.bmp *.gif)" [gradient_extract] start_color = "起始颜色" end_color = "结束颜色" +base_color = "基准颜色" steps = "中间色数量" +shade_count = "色阶数量" random = "随机" favorite = "收藏" select_color = "选择颜色" @@ -92,7 +97,7 @@ no_selection = "请先选择要删除的配色" [color_preview] title = "配色预览" -subtitle = "还在持续完善中" +subtitle = "混合布局的导入存在一定的问题,本模块还在持续完善中" import_btn = "导入" export_btn = "导出" delete = "删除" @@ -218,6 +223,10 @@ luminance_sample_count_desc = "设置明度提取面板的采样点数量(2-8 histogram = "直方图设置" histogram_scaling = "直方图缩放模式" histogram_scaling_desc = "选择直方图的缩放方式(线性/自适应)" +luminance_histogram_style = "明度直方图样式" +luminance_histogram_style_desc = "选择明度直方图的显示样式" +luminance_histogram_line = "线连接" +luminance_histogram_bar = "柱状图" histogram_mode = "直方图显示模式" histogram_mode_desc = "选择色彩提取面板的直方图类型(RGB通道/色相分布)" highlight = "区域高亮设置" @@ -236,7 +245,12 @@ gradient_color_space = "渐变颜色空间" gradient_color_space_desc = "选择渐变色插值的颜色空间" gradient_rgb = "RGB 空间" gradient_hsb = "HSB 空间" +gradient_hsl = "HSL 空间" gradient_lab = "LAB 空间" +gradient_mode = "渐变模式" +gradient_mode_desc = "选择渐变提取的模式" +gradient_mode_gradient = "双色渐变" +gradient_mode_shade = "单色渐变" language = "语言设置" language_title = "页面语言" language_desc = "选择应用程序的显示语言" diff --git a/locales/en_US.toml b/locales/en_US.toml index caaf5366deddca881497185a681405eccd33d62c..46247cf76b3e11fcac9e784e8073582c1ae50be1 100644 --- a/locales/en_US.toml +++ b/locales/en_US.toml @@ -14,8 +14,11 @@ color_preview = "Color Preview" settings = "Settings" [title_bar] -toggle_theme = "Toggle Dark/Light Mode" +toggle_theme = "Toggle Theme" toggle_fullscreen = "Fullscreen/Exit Fullscreen (F11)" +theme_light = "Light Mode" +theme_dark = "Dark Mode" +theme_auto = "System" [color_extract] favorite = "Save Palette" @@ -33,7 +36,9 @@ image_filter = "Image Files (*.png *.jpg *.jpeg *.bmp *.gif)" [gradient_extract] start_color = "Start Color" end_color = "End Color" +base_color = "Base Color" steps = "Middle Colors" +shade_count = "Shade Count" random = "Random" favorite = "Save" select_color = "Select Color" @@ -92,7 +97,7 @@ no_selection = "Please select palettes to delete first" [color_preview] title = "Color Preview" -subtitle = "Still under development" +subtitle = "Importing mixed layouts has some issues, this module is still under development" import_btn = "Import" export_btn = "Export" delete = "Delete" @@ -218,6 +223,10 @@ luminance_sample_count_desc = "Set the number of sample points for luminance ext histogram = "Histogram Settings" histogram_scaling = "Histogram Scaling Mode" histogram_scaling_desc = "Select histogram scaling method (Linear/Adaptive)" +luminance_histogram_style = "Luminance Histogram Style" +luminance_histogram_style_desc = "Select the display style for luminance histogram" +luminance_histogram_line = "Line" +luminance_histogram_bar = "Bar" histogram_mode = "Histogram Display Mode" histogram_mode_desc = "Select histogram type for color extraction panel (RGB Channels/Hue Distribution)" highlight = "Highlight Area Settings" @@ -236,7 +245,12 @@ gradient_color_space = "Gradient Color Space" gradient_color_space_desc = "Select color space for gradient interpolation" gradient_rgb = "RGB Space" gradient_hsb = "HSB Space" +gradient_hsl = "HSL Space" gradient_lab = "LAB Space" +gradient_mode = "Gradient Mode" +gradient_mode_desc = "Select the gradient extraction mode" +gradient_mode_gradient = "Two-color Gradient" +gradient_mode_shade = "Monochrome Gradient" language = "Language Settings" language_title = "Interface Language" language_desc = "Select the display language for the application" diff --git a/main.py b/main.py index b47658bbb8aa2f1119ba4b296ab8c259590fd21e..e5be5dfee576677b64a60b4fe42b30aadfc8d36f 100644 --- a/main.py +++ b/main.py @@ -205,6 +205,11 @@ def main(): logger.info("创建主窗口...") window = MainWindow() + + # 初始化标题栏主题按钮状态 + if hasattr(window, 'titleBar') and hasattr(window.titleBar, 'init_theme'): + window.titleBar.init_theme(theme_setting) + window.show() logger.info("主窗口显示完成") diff --git a/scenes_data/brand/default.svg b/scenes_data/brand/default.svg index d2422e5b66617178375cbff913e934899928a829..4f2e4fde3967336d1a39d07d6d1b155af3f2734b 100644 --- a/scenes_data/brand/default.svg +++ b/scenes_data/brand/default.svg @@ -2,17 +2,17 @@ - B - - BRAND - 您的品牌标语 + B + + BRAND + 您的品牌标语 - John Doe - 创意总监 - hello@brand.com + John Doe + 创意总监 + hello@brand.com diff --git a/scenes_data/magazine/cover.svg b/scenes_data/magazine/cover.svg new file mode 100644 index 0000000000000000000000000000000000000000..208ee5fffaad050511d660075e94cbc3d00a318c --- /dev/null +++ b/scenes_data/magazine/cover.svg @@ -0,0 +1,33 @@ + + + + + + COLOR MAGAZINE + + + + + + + 色彩 + 的力量 + + + + 探索设计中的色彩美学 + + + 01 年度色彩趋势报告 + 02 大师访谈:色彩与情感 + 03 画廊精选作品 + + + + NO. + 2026 + + + + 春季刊 | 第 12 期 + diff --git a/scenes_data/magazine/default.svg b/scenes_data/magazine/default.svg index 88a9c247d23f21566749ce30cf6ad12dd79e6ced..5cf2072e9e101fda523f448e8ffe232b0e712a31 100644 --- a/scenes_data/magazine/default.svg +++ b/scenes_data/magazine/default.svg @@ -1,26 +1,26 @@ - - - - - VOGUE DESIGN - - The Art of - Color - + + + + + 时尚设计 + + 色彩的 + 艺术 + - FEATURE - - Exploring the World of Colors - - Color is a powerful tool in design, - evoking emotions and creating visual harmony. - - Understanding color theory helps designers - create more impactful and meaningful work. - + 特辑 + + 探索色彩的世界 + + 色彩是设计中强大的工具, + 唤起情感并创造视觉和谐。 + + 理解色彩理论帮助设计师 + 创作更有影响力和意义的作品。 + - Color is the keyboard, the eyes are the harmonies, - the soul is the piano with many strings. - - 2026 Spring Edition + "色彩是琴键,眼睛是音锤, + 心灵是琴弦的钢琴。" + + 2026 春季刊 diff --git a/scenes_data/magazine/fashion.svg b/scenes_data/magazine/fashion.svg index 25eb307610a2d7830e217aa11cf3ce636ee2f57d..bde237133c6ebeb11975c88deea0a8542b59d444 100644 --- a/scenes_data/magazine/fashion.svg +++ b/scenes_data/magazine/fashion.svg @@ -1,40 +1,40 @@ - + - - + + - - FASHION WEEK - + + 时装周 + - + - STYLE - Revolution - + 风格 + 革命 + - - TRENDS 2026 - + + 2026 流行趋势 + - - - - + + + + - + - - SPRING ISSUE - $12.99 - + + 春季刊 + ¥88 + - - + + diff --git a/scenes_data/magazine/gallery.svg b/scenes_data/magazine/gallery.svg new file mode 100644 index 0000000000000000000000000000000000000000..585b610e677fa216e0ecebb3d9c7aa7634883694 --- /dev/null +++ b/scenes_data/magazine/gallery.svg @@ -0,0 +1,38 @@ + + + + + + + 色彩画廊 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 精选作品展示 | 2026春季特辑 + diff --git a/scenes_data/magazine/interview.svg b/scenes_data/magazine/interview.svg new file mode 100644 index 0000000000000000000000000000000000000000..d5b370d2d30eee1b5b77988716254a8364a8f649 --- /dev/null +++ b/scenes_data/magazine/interview.svg @@ -0,0 +1,53 @@ + + + + + + + + + 独家访谈 + 对话色彩大师 + + + + + + + + 张艺术 + 国际知名色彩顾问 + + + + + Q + + + + + + A + + + + + + + Q + + + + + + A + + + + + + + 精彩语录 + "色彩不仅是视觉体验,更是情感的载体。" + — 张艺术 + diff --git a/scenes_data/magazine/lifestyle.svg b/scenes_data/magazine/lifestyle.svg index d900ca4cb0b30d4d2fc140d8d8de4f0ebfdeeb40..68e00f471c5a8c41e74cabe09c0895d57f43f8d2 100644 --- a/scenes_data/magazine/lifestyle.svg +++ b/scenes_data/magazine/lifestyle.svg @@ -1,43 +1,43 @@ - + - - + + - - + + - LIVING - WELLNESS & HOME - + 生活家 + wellness & 家居 + - Cozy Spaces - + 温馨空间 + - The Art of - Slow Living - + 慢生活的 + 艺术 + - + - + - + - + - WINTER 2026 - $8.99 + 2026 冬季刊 + ¥58 diff --git a/scenes_data/magazine/tech.svg b/scenes_data/magazine/tech.svg index aa0c2bf675c4d10211ba5f2c29e86f3d4161a0bf..fcd93e0daa144c205717f36ac7296da9c0412867 100644 --- a/scenes_data/magazine/tech.svg +++ b/scenes_data/magazine/tech.svg @@ -1,43 +1,46 @@ - + - - + + - - - - + + + + - - TECH MAGAZINE - - #42 - + + 科技杂志 + + 第42期 + - FUTURE - IS NOW - + 未来 + 已来 + - - + + - + + + + 增长率 + +127% + + - - AI / ROBOTICS / QUANTUM / SPACE - - - - - + + 人工智能 / 机器人 / 量子计算 / 太空探索 + + diff --git a/scenes_data/mobile_ui/community.svg b/scenes_data/mobile_ui/community.svg new file mode 100644 index 0000000000000000000000000000000000000000..c15c5b4d7c9c81e3862ea8c9e2a57021ea522e81 --- /dev/null +++ b/scenes_data/mobile_ui/community.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + 9:41 + + + 社区 + + + + + + + + + #健身打卡 + + + #减脂餐 + + + + + + + L + + + Lisa + 2小时前 + + + 今天完成了5公里跑步! + 感觉太棒了 💪 + + + + 128 + + 23 + + + + + + + M + + + Mike + 5小时前 + + + 分享今天的减脂餐 🥗 + + + + + + + 86 + + + + + + + diff --git a/scenes_data/mobile_ui/layout.json b/scenes_data/mobile_ui/layout.json index c5c448e2b1ec0cb0e671b5d1c971f6eaf0a37af2..a1672f953d5a2072792144a44b37cf41cd0851a1 100644 --- a/scenes_data/mobile_ui/layout.json +++ b/scenes_data/mobile_ui/layout.json @@ -1,7 +1,7 @@ { "layout": { - "type": "grid_2x2", - "item_size": 180, - "spacing": 15 + "type": "grid_3x2", + "item_size": 120, + "spacing": 12 } -} +} \ No newline at end of file diff --git a/scenes_data/mobile_ui/music_player.svg b/scenes_data/mobile_ui/music_player.svg new file mode 100644 index 0000000000000000000000000000000000000000..09037e12e113b0c64ad8d08379e2f5e2522e4ef7 --- /dev/null +++ b/scenes_data/mobile_ui/music_player.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + 9:41 + + + + + + + + + + + + + + + + 夜曲 + 周杰伦 + + + + + + + + 2:34 + 4:12 + + + + + + + + + + + + + + + + + 播放列表 + + + + 1 + 晴天 + + + + 2 + 七里香 + diff --git a/scenes_data/mobile_ui/profile.svg b/scenes_data/mobile_ui/profile.svg new file mode 100644 index 0000000000000000000000000000000000000000..b28823c85c49af5d270abc7c0361486f2ad42895 --- /dev/null +++ b/scenes_data/mobile_ui/profile.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + 9:41 + + + + + + + + + + + + A + + + Alex Chen + + + ID: 8829341 + + + + 128 + 训练 + + + 45h + 时长 + + + 成就徽章 + 查看更多 + + + + 🏃 + + + 💪 + + + 🔥 + + + + + + + + 我的收藏 + + + + + 帮助中心 + + diff --git a/scenes_data/mobile_ui/reminder.svg b/scenes_data/mobile_ui/reminder.svg new file mode 100644 index 0000000000000000000000000000000000000000..0bdf82c7abb8887dcdead88def62c1bf4ab4f816 --- /dev/null +++ b/scenes_data/mobile_ui/reminder.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + 9:41 + + + 训练提醒 + + + + + + + + + + + + 提醒时间 + + + 07 + : + 30 + + + 重复 + + + + + + + + + + + + + + + + + + + + + + + + + 训练类型 + + + 跑步 + + + 力量 + + + + 开启提醒 + + + diff --git a/scenes_data/mobile_ui/settings.svg b/scenes_data/mobile_ui/settings.svg new file mode 100644 index 0000000000000000000000000000000000000000..24b0d625dff3a74ba163bcb25b7f4e9b3400bdc7 --- /dev/null +++ b/scenes_data/mobile_ui/settings.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + 9:41 + + + 设置 + + + + + + 账户 + + + + 个人资料 + + + + + 账号安全 + + + + 通用 + + + + 通知提醒 + + + + + + + 深色模式 + + + + + + 其他 + + + + 关于我们 + + diff --git a/scenes_data/poster/default.svg b/scenes_data/poster/default.svg index 3fee6e5e60ebe1c12436f1f21e8b40f9fe475df5..6506ff2c1cc08e637e1cc6b335ec45d6340b3b39 100644 --- a/scenes_data/poster/default.svg +++ b/scenes_data/poster/default.svg @@ -1,19 +1,19 @@ - + - - 设计 - - 创意无限 · 设计未来 - + + 设计 + + 创意无限 · 设计未来 + - - 2026.02.16 - 上海 - + + 2026.02.16 + 上海 + diff --git a/scenes_data/poster/food.svg b/scenes_data/poster/food.svg new file mode 100644 index 0000000000000000000000000000000000000000..bd0d5ecdf37569856b4136a6d3d1748a20572660 --- /dev/null +++ b/scenes_data/poster/food.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 美食盛宴 + + 品味生活 · 享受美味 + \ No newline at end of file diff --git a/scenes_data/poster/movie.svg b/scenes_data/poster/movie.svg new file mode 100644 index 0000000000000000000000000000000000000000..a0b1e43084cd983db1d0133e6061d7c03ee73f59 --- /dev/null +++ b/scenes_data/poster/movie.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + MOVIE + + 电影之夜 · 光影传奇 + + + + 2026.02.16 首映 + \ No newline at end of file diff --git a/scenes_data/poster/music.svg b/scenes_data/poster/music.svg index 4be908588400fb6e2c8751c23c39df2d86a21816..592b20a54726bf8b3a0e0d62c49700e90be3eff4 100644 --- a/scenes_data/poster/music.svg +++ b/scenes_data/poster/music.svg @@ -45,5 +45,5 @@ 15 - 票价 ¥180 + 票价 ¥180 diff --git a/scenes_data/poster/product.svg b/scenes_data/poster/product.svg index 71e2e69331c3e515767a0d1c015d813e82e69c28..70d6069b5a6db5c3d169e8c5d1936d33f7ed307c 100644 --- a/scenes_data/poster/product.svg +++ b/scenes_data/poster/product.svg @@ -39,14 +39,14 @@ - 起售价 - ¥2,199 - ¥2,999 - + 起售价 + ¥2,199 + ¥2,999 + - - 立即购买 + + 立即购买 diff --git a/scenes_data/poster/sale.svg b/scenes_data/poster/sale.svg new file mode 100644 index 0000000000000000000000000000000000000000..b88cee6a38cb805ed2afe78cef5743d8ba2d40f0 --- /dev/null +++ b/scenes_data/poster/sale.svg @@ -0,0 +1,33 @@ + + + + + + SALE + + + + + 50% + OFF + + + 限时特惠 + + + 全场包邮 + + + ¥99起 + + + 立即抢购 + + + + + + + + ¥199 + \ No newline at end of file diff --git a/scenes_data/poster/travel.svg b/scenes_data/poster/travel.svg new file mode 100644 index 0000000000000000000000000000000000000000..624e747b48e7f87669f400de36b326d30c1ef409 --- /dev/null +++ b/scenes_data/poster/travel.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + 探索世界 + + 旅行 + \ No newline at end of file diff --git a/scenes_data/scene_types.json b/scenes_data/scene_types.json index 820dc6cb953a272b2f72e60009007839e8ffbdcb..35d92261473925097722d31c45160e9828e75ba2 100644 --- a/scenes_data/scene_types.json +++ b/scenes_data/scene_types.json @@ -2,11 +2,12 @@ "version": "3.0", "scene_types": [ { - "id": "mobile_ui", - "name": "手机UI", - "icon": "phone", - "description": "手机应用界面预览", - "builtin": true + "id": "showcase", + "name": "混合", + "icon": "gallery", + "description": "混合布局预览,左侧2x2网格+右侧大图", + "builtin": true, + "default": true }, { "id": "web", @@ -57,6 +58,13 @@ "description": "杂志风格排版预览", "builtin": true }, + { + "id": "mobile_ui", + "name": "手机UI", + "icon": "phone", + "description": "手机应用界面预览", + "builtin": true + }, { "id": "custom", "name": "自定义", diff --git a/scenes_data/showcase/b_dots.svg b/scenes_data/showcase/b_dots.svg new file mode 100644 index 0000000000000000000000000000000000000000..677ee691aee6ab62dbb667cfef64714c94c4d2c7 --- /dev/null +++ b/scenes_data/showcase/b_dots.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scenes_data/showcase/c_food.svg b/scenes_data/showcase/c_food.svg new file mode 100644 index 0000000000000000000000000000000000000000..bd0d5ecdf37569856b4136a6d3d1748a20572660 --- /dev/null +++ b/scenes_data/showcase/c_food.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 美食盛宴 + + 品味生活 · 享受美味 + \ No newline at end of file diff --git a/scenes_data/showcase/illustration_botanical.svg b/scenes_data/showcase/illustration_botanical.svg new file mode 100644 index 0000000000000000000000000000000000000000..db8be51e222ffe8e96ce0fdf0f73629fdc25cd16 --- /dev/null +++ b/scenes_data/showcase/illustration_botanical.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/scenes_data/showcase/layout.json b/scenes_data/showcase/layout.json new file mode 100644 index 0000000000000000000000000000000000000000..82de299c7cdf249872c226e79bc9c402d773fa8c --- /dev/null +++ b/scenes_data/showcase/layout.json @@ -0,0 +1,39 @@ +{ + "layout": { + "type": "mixed", + "item_size": 180, + "spacing": 15 + }, + "scenes": [ + { + "id": "pattern_geo", + "name": "几何图案", + "file": "pattern_geo.svg", + "description": "几何图形混合排列,展示配色在图案设计中的效果" + }, + { + "id": "pattern_dots", + "name": "波点图案", + "file": "b_dots.svg", + "description": "不同大小的圆点排列组合,活泼有趣的波点设计" + }, + { + "id": "illustration_botanical", + "name": "植物插画", + "file": "illustration_botanical.svg", + "description": "简约线条植物插画,展示配色在自然主题中的应用" + }, + { + "id": "poster_food", + "name": "美食海报", + "file": "c_food.svg", + "description": "美食主题海报设计,展示配色在餐饮行业的应用" + }, + { + "id": "illustration_cityscape", + "name": "城市剪影", + "file": "z_cityscape.svg", + "description": "现代都市天际线插画,展示配色在城市景观中的视觉效果" + } + ] +} diff --git a/scenes_data/showcase/pattern_geo.svg b/scenes_data/showcase/pattern_geo.svg new file mode 100644 index 0000000000000000000000000000000000000000..985980eefc0d66492daba768dbb3035eceedf18d --- /dev/null +++ b/scenes_data/showcase/pattern_geo.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scenes_data/showcase/z_cityscape.svg b/scenes_data/showcase/z_cityscape.svg new file mode 100644 index 0000000000000000000000000000000000000000..a6ceac17b457baff397e3cf16d2ce3fb4b37bdfb --- /dev/null +++ b/scenes_data/showcase/z_cityscape.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scenes_data/typography/code.svg b/scenes_data/typography/code.svg new file mode 100644 index 0000000000000000000000000000000000000000..7ca34be4ee8d46e6c02ec8e88a3e0825530327bf --- /dev/null +++ b/scenes_data/typography/code.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + theme.js + + + + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + + + // 主题配置 + + + const + theme + = + { + + + primary: + '#ff6b6b' + , + + secondary: + '#4ecdc4' + , + + background: + '#1a1a1a' + , + + text: + '#ffffff' + + + }; + + + + JavaScript + Ln 8, Col 1 + diff --git a/scenes_data/typography/default.svg b/scenes_data/typography/default.svg index 45aa715ff99a7aeec98f309304ed62c1465d4bb2..43ba66a53c6a04cb20599607d54a404f59b415e2 100644 --- a/scenes_data/typography/default.svg +++ b/scenes_data/typography/default.svg @@ -1,17 +1,17 @@ - - - + + + - - - - All - Bodies - Are Good - Bodies - - - + + + + 色彩 + 是设计的 + 灵魂 + 与语言 + + + - + diff --git a/scenes_data/typography/editorial.svg b/scenes_data/typography/editorial.svg index cefb85d98c98bdc97562a5f36a3f10df82c46fec..cb8156773a7c7061194e3f0b0eefd6b8d7ae2548 100644 --- a/scenes_data/typography/editorial.svg +++ b/scenes_data/typography/editorial.svg @@ -1,37 +1,37 @@ - + - - + + - - + + - FEATURE - + 特辑 + 设计的力量 - + 探索色彩与排版的无限可能 - + By Design Team · 2026年2月 - + - - + + - - - - + + + + - + - - - + + + - 01 + 01 diff --git a/scenes_data/typography/hierarchy.svg b/scenes_data/typography/hierarchy.svg new file mode 100644 index 0000000000000000000000000000000000000000..2ab36bc2b734e4847afd822d0fe3133f77310865 --- /dev/null +++ b/scenes_data/typography/hierarchy.svg @@ -0,0 +1,38 @@ + + + + + + + + + 设计系统指南 + + + 色彩与排版规范 + + + 1.1 色彩理论基础 + + + + + + + + 注意事项 + + + 最后更新:2026年4月 + + + + + + + + + + + + diff --git a/scenes_data/typography/infographic.svg b/scenes_data/typography/infographic.svg new file mode 100644 index 0000000000000000000000000000000000000000..501f5ddcb74e727dbb2a452f543fbbdd39c10a1f --- /dev/null +++ b/scenes_data/typography/infographic.svg @@ -0,0 +1,65 @@ + + + + + + 设计流程概览 + + + + 1 + 调研 + + + + 2 + 概念 + + + + 3 + 设计 + + + + 4 + 交付 + + + + + + + + + + + + + + + + 85% + 用户满意度 + + + + + 120+ + 完成项目 + + + + + 4.9 + 平均评分 + + + + + 24h + 响应时间 + + + + diff --git a/scenes_data/typography/minimal.svg b/scenes_data/typography/minimal.svg index 9343373775b2e3ea8fd770dd1be3271a5b8dd5bb..c37f6e2f7e4d98da71081326d63c9bdaebdcc53e 100644 --- a/scenes_data/typography/minimal.svg +++ b/scenes_data/typography/minimal.svg @@ -1,19 +1,18 @@ - + - - + + - - + + - Less - is More - + 少即是多 + - Minimalist Design Philosophy - + 极简主义设计理念 + - - - + + + diff --git a/scenes_data/typography/poster.svg b/scenes_data/typography/poster.svg index 722b8ceac1cef4fa10ff0fbb016e725d59fb3f28..ff3e108cfa54182717384561bcf90e72a08870d3 100644 --- a/scenes_data/typography/poster.svg +++ b/scenes_data/typography/poster.svg @@ -1,29 +1,29 @@ - + - - + + - - - + + + - + - CREATE - BOLD - + 创造 + 大胆 + - Design Conference 2026 - + 2026 设计大会 + - - MARCH 15-17 · SHANGHAI - + + 3月15-17日 · 上海 + - - - + + + diff --git a/scenes_data/typography/quote.svg b/scenes_data/typography/quote.svg new file mode 100644 index 0000000000000000000000000000000000000000..bacdf4b4d66f1d3083671a8d85991643da31cbeb --- /dev/null +++ b/scenes_data/typography/quote.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + " + + + + + + + + + + " + + + — 保罗·兰德 + 著名平面设计师 + + + + + + + + + diff --git a/scenes_data/web/about.svg b/scenes_data/web/about.svg new file mode 100644 index 0000000000000000000000000000000000000000..68193b9b1b2c11175521e16517c3c4c43715dd6f --- /dev/null +++ b/scenes_data/web/about.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + 关于我们 + 创新驱动,技术引领 + + + 发展历程 + + + + + + + 2020 + 公司成立 + + + + 2022 + 产品发布 + + + + 2024 + 用户破百万 + + + + 2026 + 全球拓展 + + + 核心团队 + + + + 张明 + CEO + + + + 李华 + CTO + + + + 王芳 + 设计总监 + + + + 陈伟 + 产品总监 + diff --git a/scenes_data/web/article.svg b/scenes_data/web/article.svg new file mode 100644 index 0000000000000000000000000000000000000000..374e7c6e57eeff51c53fbbb3343c2b568787d3c9 --- /dev/null +++ b/scenes_data/web/article.svg @@ -0,0 +1,51 @@ + + + + + + + 首页 + 文章 + 画廊 + 关于 + + + 色彩心理学:如何用颜色讲述故事 + + + + 作者:李明 | 设计总监 + 2026年3月15日 + + + + + + + + + + + + + + + + + + + + + + + + + + + + "每一种颜色都有其独特的语言, + 设计师的工作就是翻译这种语言。" + + + - 24 - + diff --git a/scenes_data/web/contact.svg b/scenes_data/web/contact.svg new file mode 100644 index 0000000000000000000000000000000000000000..52e3972c58ee7d25904656f746ecd450d136a0da --- /dev/null +++ b/scenes_data/web/contact.svg @@ -0,0 +1,60 @@ + + + + + + + + 首页 + 产品 + 关于 + 联系 + + + 联系我们 + 有任何问题?我们随时为您服务 + + + + + + + 公司地址 + 北京市朝阳区科技园区A座 + + + + 联系电话 + 400-123-4567 + + + + 电子邮箱 + contact@example.com + + + + + + 发送消息 + + + + 您的姓名 + + + + 您的邮箱 + + + + 消息主题 + + + + 请输入您的消息... + + + + 发送 + diff --git a/scenes_data/web/documentation.svg b/scenes_data/web/documentation.svg new file mode 100644 index 0000000000000000000000000000000000000000..be07e88cf6463df50b1e699cacdbcb0f53da25cf --- /dev/null +++ b/scenes_data/web/documentation.svg @@ -0,0 +1,69 @@ + + + + + + + + Docs + + + + 搜索文档... + + + + v2.0.0 + + + + + + 快速开始 + + 安装指南 + + 基础配置 + 第一个应用 + + + 核心概念 + 组件系统 + 状态管理 + 路由配置 + + + API参考 + + + + + + 文档 > 快速开始 > 安装指南 + + + 安装指南 + + + + 本文档将指导您完成安装和基本配置。 + 整个过程大约需要5分钟。 + + + + + + $ npm install my-app + + my-app@2.0.0 + added 42 packages in 3s + $ npm run dev + + + + 复制 + + + + 💡 + 提示: 确保您的Node.js版本 >= 16.0 + diff --git a/scenes_data/web/landing_page.svg b/scenes_data/web/landing_page.svg new file mode 100644 index 0000000000000000000000000000000000000000..8b00f9f422527a7ff0713e1589adbe4661073a28 --- /dev/null +++ b/scenes_data/web/landing_page.svg @@ -0,0 +1,50 @@ + + + + + + + + Brand + + + 产品 + 特性 + 定价 + + + + + + + + + 革新你的工作方式 + 强大的工具,简洁的体验 + + + + 免费开始 + + + 了解更多 + + + + + + 极速性能 + 毫秒级响应 + + + + + 安全可靠 + 企业级加密 + + + + + 全球部署 + 覆盖200+国家 + diff --git a/scenes_data/web/layout.json b/scenes_data/web/layout.json index 39b6e309eca092978971c991b7a31aa95d59b137..c5d01cae6089512ccd52047cf62c581a0b312ad7 100644 --- a/scenes_data/web/layout.json +++ b/scenes_data/web/layout.json @@ -11,12 +11,24 @@ "file": "default.svg", "description": "通用企业官网首页,包含导航、Hero区域和功能卡片" }, + { + "id": "landing_page", + "name": "营销落地页", + "file": "landing_page.svg", + "description": "营销落地页,包含大标题、CTA按钮和特性列表" + }, { "id": "ecommerce", "name": "电商页面", "file": "ecommerce.svg", "description": "电商产品列表页,包含搜索框、分类标签和产品网格" }, + { + "id": "pricing", + "name": "定价页面", + "file": "pricing.svg", + "description": "定价页面,包含价格卡片和功能对比" + }, { "id": "blog", "name": "博客页面", @@ -35,17 +47,35 @@ "file": "dashboard.svg", "description": "网页版数据仪表盘,包含统计卡片、折线图和活动列表" }, - { - "id": "login", - "name": "登录页面", - "file": "login.svg", - "description": "左右分栏式登录页面,包含装饰区域和登录表单" - }, { "id": "admin_dashboard", "name": "后台仪表盘", "file": "admin_dashboard.svg", "description": "完整的后台管理系统界面,包含侧边栏、日历、用户列表、统计卡片和数据图表" + }, + { + "id": "documentation", + "name": "文档页面", + "file": "documentation.svg", + "description": "文档页面,包含侧边栏导航和代码块" + }, + { + "id": "about", + "name": "关于我们", + "file": "about.svg", + "description": "关于我们页面,包含团队介绍和时间线" + }, + { + "id": "contact", + "name": "联系页面", + "file": "contact.svg", + "description": "联系页面,包含表单、地图和联系信息" + }, + { + "id": "login", + "name": "登录页面", + "file": "login.svg", + "description": "左右分栏式登录页面,包含装饰区域和登录表单" } ] -} \ No newline at end of file +} diff --git a/scenes_data/web/pricing.svg b/scenes_data/web/pricing.svg new file mode 100644 index 0000000000000000000000000000000000000000..954bdf8a2992a0da129bec40392b5b8b70fc39d6 --- /dev/null +++ b/scenes_data/web/pricing.svg @@ -0,0 +1,76 @@ + + + + + + + + + + 选择适合您的方案 + 随时升级或降级,无隐藏费用 + + + + 基础版 + ¥0 + /月 + + + + 1个项目 + + + 基础分析 + + + 社区支持 + + + 开始使用 + + + + + 推荐 + + 专业版 + ¥99 + /月 + + + 无限项目 + + + 高级分析 + + + 优先支持 + + + API访问 + + + 立即升级 + + + + 企业版 + ¥299 + /月 + + + 所有专业版功能 + + + 专属客户经理 + + + 定制开发 + + + SLA保障 + + + 联系销售 + diff --git a/ui/canvases.py b/ui/canvases.py index e9f7ae10ff767acc60defb62086e94b2dd30e74f..c92d28369031f0a19d74e966cd55307104612899 100644 --- a/ui/canvases.py +++ b/ui/canvases.py @@ -575,8 +575,7 @@ class BaseCanvas(QWidget): elif not self._is_loading: # 没有图片且不在加载状态时显示提示文字 painter.setPen(get_canvas_empty_text_color()) - font = QFont() - font.setPointSize(14) + font = QFont("Arial", 11) painter.setFont(font) text = tr('canvases.click_to_import') text_rect = painter.boundingRect(self.rect(), Qt.AlignmentFlag.AlignCenter, text) diff --git a/ui/color_preview.py b/ui/color_preview.py index 85ca0a6c0559310332debb6e107ece36668200ad..86f6537be3b281b5b0f6c8d90882f213a73faee7 100644 --- a/ui/color_preview.py +++ b/ui/color_preview.py @@ -1109,9 +1109,18 @@ class ScrollVLayout(BaseLayout): self._scroll_area = ScrollArea() self._scroll_area.setWidgetResizable(True) - self._scroll_area.setStyleSheet("QScrollArea { border: none; }") + self._scroll_area.setStyleSheet(""" + QScrollArea { + border: none; + background: transparent; + } + QScrollArea > QWidget > QWidget { + background: transparent; + } + """) corner_widget = QWidget() + corner_widget.setStyleSheet("background: transparent;") self._scroll_area.setCornerWidget(corner_widget) self._content_widget = QWidget() @@ -1173,9 +1182,18 @@ class ScrollHLayout(BaseLayout): self._scroll_area = ScrollArea() self._scroll_area.setWidgetResizable(True) - self._scroll_area.setStyleSheet("QScrollArea { border: none; }") + self._scroll_area.setStyleSheet(""" + QScrollArea { + border: none; + background: transparent; + } + QScrollArea > QWidget > QWidget { + background: transparent; + } + """) corner_widget = QWidget() + corner_widget.setStyleSheet("background: transparent;") self._scroll_area.setCornerWidget(corner_widget) self._content_widget = QWidget() @@ -1221,9 +1239,18 @@ class GridLayout(BaseLayout): self._scroll_area = ScrollArea() self._scroll_area.setWidgetResizable(True) - self._scroll_area.setStyleSheet("QScrollArea { border: none; }") + self._scroll_area.setStyleSheet(""" + QScrollArea { + border: none; + background: transparent; + } + QScrollArea > QWidget > QWidget { + background: transparent; + } + """) corner_widget = QWidget() + corner_widget.setStyleSheet("background: transparent;") self._scroll_area.setCornerWidget(corner_widget) self._content_widget = QWidget() @@ -1422,11 +1449,17 @@ class PreviewSceneSelector(ComboBox): self.setEnabled(False) else: self.setEnabled(True) - for scene_type in self._scene_types: + default_index = 0 + for index, scene_type in enumerate(self._scene_types): scene_id = scene_type.get("id", "") scene_name = scene_type.get("name", scene_id) self.addItem(scene_name) self.setItemData(self.count() - 1, scene_id) + # 检查是否为默认场景 + if scene_type.get("default", False): + default_index = index + # 设置默认选中项 + self.setCurrentIndex(default_index) def _on_selection_changed(self, text: str): """处理选择变化""" @@ -1446,7 +1479,7 @@ class PreviewSceneSelector(ComboBox): def get_current_scene(self) -> str: """获取当前场景ID""" - return self.itemData(self.currentIndex()) or "mobile_ui" + return self.itemData(self.currentIndex()) or "showcase" def reload_scenes(self): """重新加载场景列表""" @@ -1483,7 +1516,7 @@ class MixedPreviewPanel(QWidget): parent: 父控件 """ self._colors: List[str] = [] - self._current_scene: str = "mobile_ui" + self._current_scene: str = "showcase" self._current_layout: Optional[BaseLayout] = None self._svg_preview: Optional[SVGPreviewWidget] = None self._custom_svg_path: Optional[str] = None @@ -1672,7 +1705,7 @@ class PreviewToolbar(QWidget): Args: parent: 父控件 """ - self._current_scene = "mobile_ui" + self._current_scene = "showcase" super().__init__(parent) self.setup_ui() self._update_styles() @@ -1829,7 +1862,7 @@ class ColorPreviewInterface(QWidget): self._favorites = [] self._current_index = 0 self._current_colors: list[str] = [] - self._current_scene = "mobile_ui" + self._current_scene = "showcase" self._current_svg_path = "" self._hex_visible = self._config_manager.get('settings.hex_visible', True) self._scene_types_loaded = False diff --git a/ui/gradient_extract.py b/ui/gradient_extract.py index f2cbe2e601f6cbb9de6b7338a43c983229564d4b..538b9c703363cfa5dfe2444c1d4d1cc2d41b755e 100644 --- a/ui/gradient_extract.py +++ b/ui/gradient_extract.py @@ -14,7 +14,7 @@ from qfluentwidgets import ( ) # 项目模块导入 -from core import generate_gradient, generate_random_gradient, get_color_info +from core import generate_gradient, generate_random_gradient, generate_lightness_shades, generate_random_lightness_shade, get_color_info from core import get_config_manager from core.logger import get_logger, log_user_action from ui.cards import ColorCard @@ -35,10 +35,11 @@ class ColorDot(QWidget): self._radius = 12 self.setFixedSize(24, 24) self.setCursor(Qt.CursorShape.PointingHandCursor) - self._update_style() + self._update_styles() + qconfig.themeChangedFinished.connect(self._update_styles) - def _update_style(self): - """更新样式""" + def _update_styles(self): + """更新样式以适配主题""" border_color = get_border_color() self.setStyleSheet(f""" ColorDot {{ @@ -49,20 +50,14 @@ class ColorDot(QWidget): """) def paintEvent(self, event): - """绘制事件,确保背景色显示""" + """绘制颜色圆""" painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing) - # 绘制背景圆 painter.setPen(Qt.PenStyle.NoPen) painter.setBrush(QColor(self._color)) - painter.drawEllipse(self.rect().center(), self._radius, self._radius) - - # 绘制边框 - border_color = get_border_color() - painter.setPen(QColor(border_color)) - painter.setBrush(Qt.BrushStyle.NoBrush) - painter.drawEllipse(self.rect().center(), self._radius - 1, self._radius - 1) + # 留出1像素边距,避免边缘被截断 + painter.drawEllipse(self.rect().adjusted(1, 1, -1, -1)) def set_color(self, hex_color: str): """设置颜色 @@ -71,7 +66,7 @@ class ColorDot(QWidget): hex_color: HEX颜色值,如"#FF0000" """ self._color = hex_color - self._update_style() + self._update_styles() self.update() def get_color(self) -> str: @@ -261,12 +256,14 @@ class GradientExtractInterface(QWidget): self.setObjectName('gradientExtract') self._config_manager = get_config_manager() self._color_space = self._config_manager.get('settings.gradient_color_space', 'lab') + self._gradient_mode = self._config_manager.get('settings.gradient_mode', 'gradient') self._start_color = "#FF5733" self._end_color = "#33FF57" self._steps = 2 # 默认2个中间色,共4个颜色 self.setup_ui() self._update_styles() + self._apply_gradient_mode_ui() qconfig.themeChangedFinished.connect(self._update_styles) get_locale_manager().language_changed.connect(self._on_language_changed) @@ -325,8 +322,10 @@ class GradientExtractInterface(QWidget): control_layout.addLayout(start_color_layout) # 结束颜色选择 - end_color_layout = QHBoxLayout() - end_color_layout.setSpacing(8) + self.end_color_widget = QWidget() + end_color_inner_layout = QHBoxLayout(self.end_color_widget) + end_color_inner_layout.setContentsMargins(0, 0, 0, 0) + end_color_inner_layout.setSpacing(8) self.end_color_dot = ColorDot(self._end_color) self.end_color_label = QLabel(tr('gradient_extract.end_color')) self.end_color_label.setFixedWidth(56) @@ -340,12 +339,12 @@ class GradientExtractInterface(QWidget): self.end_color_input.textChanged.connect(self._on_end_color_text_changed) self.end_color_input.editingFinished.connect(self._on_end_color_editing_finished) self.end_color_dot.clicked.connect(self._open_end_color_picker) - end_color_layout.addStretch() - end_color_layout.addWidget(self.end_color_dot) - end_color_layout.addWidget(self.end_color_label) - end_color_layout.addWidget(self.end_color_input) - end_color_layout.addStretch() - control_layout.addLayout(end_color_layout) + end_color_inner_layout.addStretch() + end_color_inner_layout.addWidget(self.end_color_dot) + end_color_inner_layout.addWidget(self.end_color_label) + end_color_inner_layout.addWidget(self.end_color_input) + end_color_inner_layout.addStretch() + control_layout.addWidget(self.end_color_widget) # 中间色数量控制 steps_layout = QVBoxLayout() @@ -423,7 +422,6 @@ class GradientExtractInterface(QWidget): self.steps_label.setStyleSheet(f"color: {text_color.name()}; font-size: 13px;") self.steps_value_label.setStyleSheet(f"color: {secondary_text.name()}; font-size: 13px;") - # 更新输入框样式(与配色管理一致) self._update_hex_input_style() def _update_hex_input_style(self): @@ -450,9 +448,13 @@ class GradientExtractInterface(QWidget): def _on_language_changed(self, language_code): """语言切换回调""" - self.start_color_label.setText(tr('gradient_extract.start_color')) + if self._gradient_mode == 'shade': + self.start_color_label.setText(tr('gradient_extract.base_color')) + self.steps_label.setText(tr('gradient_extract.shade_count')) + else: + self.start_color_label.setText(tr('gradient_extract.start_color')) + self.steps_label.setText(tr('gradient_extract.steps')) self.end_color_label.setText(tr('gradient_extract.end_color')) - self.steps_label.setText(tr('gradient_extract.steps')) self.random_button.setText(tr('gradient_extract.random')) self.favorite_button.setText(tr('gradient_extract.favorite')) @@ -643,32 +645,43 @@ class GradientExtractInterface(QWidget): def _generate_gradient(self): """生成渐变色""" try: - colors = generate_gradient( - self._start_color, - self._end_color, - self._steps, - self._color_space - ) + if self._gradient_mode == 'shade': + colors = generate_lightness_shades(self._start_color, self._steps, self._color_space) + else: + colors = generate_gradient( + self._start_color, + self._end_color, + self._steps, + self._color_space + ) self._current_colors = colors self.gradient_preview.set_colors(colors) self.card_panel.set_colors(colors) - logger.debug(f"生成渐变成功: start={self._start_color}, end={self._end_color}, steps={self._steps}, color_space={self._color_space}") - except Exception as e: - logger.error(f"生成渐变失败: start={self._start_color}, end={self._end_color}, steps={self._steps}, error={e}", exc_info=True) + logger.debug(f"生成渐变成功: mode={self._gradient_mode}, start={self._start_color}, steps={self._steps}") + except (ValueError, TypeError) as e: + logger.error(f"生成渐变失败: mode={self._gradient_mode}, error={e}", exc_info=True) def _on_random_clicked(self): """随机按钮点击""" - start_hex, end_hex, colors = generate_random_gradient(self._steps, self._color_space) - self._start_color = start_hex - self._end_color = end_hex - self.start_color_dot.set_color(start_hex) - self.end_color_dot.set_color(end_hex) - self.start_color_input.setText(start_hex) - self.end_color_input.setText(end_hex) + if self._gradient_mode == 'shade': + base_hex, colors = generate_random_lightness_shade(self._steps, self._color_space) + self._start_color = base_hex + self.start_color_dot.set_color(base_hex) + self.start_color_input.setText(base_hex) + log_user_action("random_lightness_shade", {"base": base_hex, "count": self._steps}) + else: + start_hex, end_hex, colors = generate_random_gradient(self._steps, self._color_space) + self._start_color = start_hex + self._end_color = end_hex + self.start_color_dot.set_color(start_hex) + self.end_color_dot.set_color(end_hex) + self.start_color_input.setText(start_hex) + self.end_color_input.setText(end_hex) + log_user_action("random_gradient", {"start": start_hex, "end": end_hex, "steps": self._steps}) + self._current_colors = colors self.gradient_preview.set_colors(colors) self.card_panel.set_colors(colors) - log_user_action("random_gradient", {"start": start_hex, "end": end_hex, "steps": self._steps, "color_count": len(colors)}) def _on_favorite_clicked(self): """收藏按钮点击""" @@ -739,6 +752,38 @@ class GradientExtractInterface(QWidget): log_user_action("change_color_space", {"color_space": color_space}) self._generate_gradient() + def set_gradient_mode(self, mode: str): + """设置渐变模式 + + Args: + mode: 'gradient' 或 'shade' + """ + self._gradient_mode = mode + self._apply_gradient_mode_ui() + self._generate_gradient() + log_user_action("change_gradient_mode", {"mode": mode}) + + def _apply_gradient_mode_ui(self): + """根据当前渐变模式更新UI""" + is_shade = self._gradient_mode == 'shade' + + self.end_color_widget.setVisible(not is_shade) + + if is_shade: + self.start_color_label.setText(tr('gradient_extract.base_color')) + self.steps_label.setText(tr('gradient_extract.shade_count')) + self.steps_slider.setMinimum(3) + self.steps_slider.setMaximum(13) + if self._steps < 3: + self.steps_slider.setValue(3) + else: + self.start_color_label.setText(tr('gradient_extract.start_color')) + self.steps_label.setText(tr('gradient_extract.steps')) + self.steps_slider.setMinimum(1) + self.steps_slider.setMaximum(10) + if self._steps > 10: + self.steps_slider.setValue(10) + def set_hex_visible(self, visible: bool): """设置16进制显示""" self.card_panel.set_hex_visible(visible) diff --git a/ui/histograms.py b/ui/histograms.py index 62507bcd2751f5b3ecb927040a88470b73cb3838..f55e0638238f3cd600a07bee368fc16b7c40fa7d 100644 --- a/ui/histograms.py +++ b/ui/histograms.py @@ -2,7 +2,7 @@ import math from typing import List from PySide6.QtCore import Qt, Signal -from PySide6.QtGui import QColor, QFont, QLinearGradient, QPainter, QPen, QMouseEvent +from PySide6.QtGui import QColor, QFont, QLinearGradient, QPainter, QPainterPath, QPen, QMouseEvent from PySide6.QtWidgets import QWidget # 项目模块导入 @@ -290,6 +290,7 @@ class LuminanceHistogramWidget(BaseHistogram): self._highlight_zones = [] # 高亮显示的区域列表 self._pressed_zone = -1 # 当前按下的Zone self._current_zone = -1 # 当前选中的Zone + self._histogram_style = "line" # 直方图样式: "line" 或 "bar" # 启用鼠标跟踪 self.setMouseTracking(True) @@ -299,6 +300,16 @@ class LuminanceHistogramWidget(BaseHistogram): self._histogram_service.luminance_histogram_ready.connect(self._on_histogram_ready) self._histogram_service.error.connect(self._on_histogram_error) + def set_histogram_style(self, style: str): + """设置直方图样式 + + Args: + style: 样式类型,"line" 为线连接样式,"bar" 为柱状图样式 + """ + if style in ("line", "bar") and style != self._histogram_style: + self._histogram_style = style + self.update() + def set_image(self, image): """设置图片并异步计算直方图""" if image is None or image.isNull(): @@ -359,13 +370,60 @@ class LuminanceHistogramWidget(BaseHistogram): return labels[zone] if 0 <= zone <= 8 else "--" def _draw_histogram(self, painter: QPainter, x: int, y: int, width: int, height: int): - """绘制直方图曲线 - LR风格""" + """绘制直方图 - 支持线连接和柱状图两种样式""" if self._max_count == 0: return # 绘制Zone背景色块(类似LR的风格) self._draw_zone_background(painter, x, y, width, height) + # 根据样式选择绘制方式 + if self._histogram_style == "bar": + self._draw_bar_histogram(painter, x, y, width, height) + else: + self._draw_line_histogram(painter, x, y, width, height) + + def _draw_line_histogram(self, painter: QPainter, x: int, y: int, width: int, height: int): + """绘制线连接样式直方图""" + bar_width = width / 256.0 + + # 计算每个点的坐标 + points = [] + for i in range(256): + bar_height = self._calculate_bar_height(self._histogram[i], self._max_count, height) + point_x = x + i * bar_width + point_y = y + height - bar_height + points.append((point_x, point_y)) + + # 创建填充路径(闭合区域) + fill_path = QPainterPath() + fill_path.moveTo(points[0][0], y + height) # 左下角 + for px, py in points: + fill_path.lineTo(px, py) + fill_path.lineTo(points[-1][0], y + height) # 右下角 + fill_path.closeSubpath() + + # 绘制渐变填充(从线条颜色到透明) + gradient = QLinearGradient(x, y, x, y + height) + line_color = get_histogram_text_color() + gradient.setColorAt(0, line_color) # 顶部使用线条颜色 + gradient.setColorAt(1, QColor(0, 0, 0, 0)) # 底部透明 + painter.fillPath(fill_path, gradient) + + # 绘制轮廓线 + line_path = QPainterPath() + line_path.moveTo(points[0][0], points[0][1]) + for px, py in points[1:]: + line_path.lineTo(px, py) + + painter.setPen(QPen(line_color, 1.5)) + painter.setBrush(Qt.BrushStyle.NoBrush) + painter.drawPath(line_path) + + def _draw_bar_histogram(self, painter: QPainter, x: int, y: int, width: int, height: int): + """绘制柱状图样式直方图""" + bar_width = width / 256.0 + # 使用渐变填充,从浅灰到白色 gradient = QLinearGradient(x, y + height, x, y) gradient.setColorAt(0, get_histogram_axis_color()) @@ -374,16 +432,11 @@ class LuminanceHistogramWidget(BaseHistogram): painter.setPen(Qt.PenStyle.NoPen) painter.setBrush(gradient) - # 每个明度值对应的宽度 - bar_width = width / 256.0 - # 绘制直方图柱子 for i in range(256): - # 计算柱子高度 - 使用基类的计算方法 bar_height = self._calculate_bar_height(self._histogram[i], self._max_count, height) if bar_height > 0: - # 绘制柱子 bar_x = x + i * bar_width bar_y = y + height - bar_height diff --git a/ui/luminance_extract.py b/ui/luminance_extract.py index f061e1c6970a8193aaafa67d563aeedc6223ed7f..658b21ac5792249825eafc21efb0fe78ff153ad8 100644 --- a/ui/luminance_extract.py +++ b/ui/luminance_extract.py @@ -11,7 +11,7 @@ from PySide6.QtCore import Qt, QTimer, Signal from PySide6.QtWidgets import QFileDialog, QSplitter, QVBoxLayout, QWidget # 项目模块导入 -from core import LuminanceService +from core import LuminanceService, get_config_manager from core.logger import get_logger, log_user_action from utils import tr, get_locale_manager, get_default_image_directory, get_last_directory, set_last_directory from .canvases import LuminanceCanvas @@ -62,11 +62,28 @@ class LuminanceExtractInterface(QWidget): self.histogram_widget.setMaximumHeight(250) self.splitter.addWidget(self.histogram_widget) + # 初始化直方图样式 + self._init_histogram_style() + self.splitter.setSizes([400, 150]) # 设置信号连接 self._setup_connections() + def _init_histogram_style(self): + """初始化直方图样式""" + config_manager = get_config_manager() + style = config_manager.get('settings.luminance_histogram_style', 'line') + self.histogram_widget.set_histogram_style(style) + + def set_histogram_style(self, style: str): + """设置直方图样式(由设置界面调用) + + Args: + style: 样式类型,"line" 或 "bar" + """ + self.histogram_widget.set_histogram_style(style) + def _setup_connections(self): """设置信号连接""" self.luminance_canvas.luminance_picked.connect(self.on_luminance_picked) diff --git a/ui/main_window.py b/ui/main_window.py index 60c2f0bfa9f3f4c0801b785f88783dd1c601760a..57f1a0644064be5fe0fd44cf18ca12eae40f59ca 100644 --- a/ui/main_window.py +++ b/ui/main_window.py @@ -35,15 +35,17 @@ _TOOLBUTTON_STYLE = """ class CustomTitleBar(FluentTitleBar): - """自定义标题栏,添加深色模式切换按钮和全屏切换按钮""" + """自定义标题栏,添加主题切换按钮和全屏切换按钮""" def __init__(self, parent): super().__init__(parent) - # 创建深色模式切换按钮 + # 主题模式:light/dark/auto + self._theme_mode = 'auto' + + # 创建主题切换按钮 self.themeButton = ToolButton(self) self.themeButton.setFixedSize(40, 32) - self.themeButton.setToolTip(tr('title_bar.toggle_theme')) self.themeButton.setStyleSheet(_TOOLBUTTON_STYLE) self._update_theme_icon() @@ -60,26 +62,51 @@ class CustomTitleBar(FluentTitleBar): # 连接点击事件 self.fullscreenButton.clicked.connect(self._toggle_fullscreen) - # 将按钮插入到最小化按钮之前(深色模式按钮在前,全屏按钮在后) + # 将按钮插入到最小化按钮之前(主题按钮在前,全屏按钮在后) index = self.buttonLayout.indexOf(self.minBtn) self.buttonLayout.insertWidget(index, self.themeButton) self.buttonLayout.insertWidget(index + 1, self.fullscreenButton) + def init_theme(self, mode: str): + """初始化主题模式 + + Args: + mode: 主题模式 (light/dark/auto) + """ + self._theme_mode = mode + self._update_theme_icon() + def _toggle_theme(self): - """切换主题""" - if isDarkTheme(): + """切换主题(三态循环:浅色→深色→跟随系统→浅色)""" + mode_cycle = ['light', 'dark', 'auto'] + current_index = mode_cycle.index(self._theme_mode) + next_index = (current_index + 1) % len(mode_cycle) + next_mode = mode_cycle[next_index] + + self._apply_theme_mode(next_mode) + + def _apply_theme_mode(self, mode: str): + """应用主题模式 + + Args: + mode: 主题模式 (light/dark/auto) + """ + self._theme_mode = mode + + if mode == 'light': setTheme(Theme.LIGHT) - theme_value = 'light' - else: + elif mode == 'dark': setTheme(Theme.DARK) - theme_value = 'dark' + else: # auto + setTheme(Theme.AUTO) + self._update_theme_icon() - # 重新应用按钮样式以覆盖 Fluent 主题样式 self._apply_theme_button_style() - # 保存主题配置 + + # 保存配置 from core import get_config_manager config_manager = get_config_manager() - config_manager.set('settings.theme', theme_value) + config_manager.set('settings.theme', mode) config_manager.save() def _apply_theme_button_style(self): @@ -100,9 +127,20 @@ class CustomTitleBar(FluentTitleBar): self.fullscreenButton.setStyleSheet(style_sheet) def _update_theme_icon(self): - """根据当前主题更新按钮图标""" - # 使用 CONSTRACT(对比度)图标作为主题切换按钮 - self.themeButton.setIcon(FluentIcon.CONSTRACT) + """根据当前主题模式更新按钮图标和提示""" + if self._theme_mode == 'light': + self.themeButton.setIcon(FluentIcon.BRIGHTNESS) + elif self._theme_mode == 'dark': + self.themeButton.setIcon(FluentIcon.QUIET_HOURS) + else: # auto + self.themeButton.setIcon(FluentIcon.SYNC) + + tooltip_map = { + 'light': tr('title_bar.theme_light'), + 'dark': tr('title_bar.theme_dark'), + 'auto': tr('title_bar.theme_auto') + } + self.themeButton.setToolTip(tooltip_map[self._theme_mode]) def _toggle_fullscreen(self): """切换全屏/窗口模式""" @@ -123,7 +161,7 @@ class CustomTitleBar(FluentTitleBar): def update_texts(self): """更新界面文本""" - self.themeButton.setToolTip(tr('title_bar.toggle_theme')) + self._update_theme_icon() self.fullscreenButton.setToolTip(tr('title_bar.toggle_fullscreen')) @@ -332,6 +370,11 @@ class MainWindow(FluentWindow): self._on_histogram_scaling_mode_changed ) + # 连接明度直方图样式改变信号到明度提取界面 + settings_interface.luminance_histogram_style_changed.connect( + luminance_extract_interface.set_histogram_style + ) + # 连接色轮模式改变信号到配色生成界面 settings_interface.color_wheel_mode_changed.connect( color_generation_interface.set_color_wheel_mode @@ -342,6 +385,11 @@ class MainWindow(FluentWindow): gradient_extract_interface.set_color_space ) + # 连接渐变模式改变信号到渐变提取界面 + settings_interface.gradient_mode_changed.connect( + gradient_extract_interface.set_gradient_mode + ) + # 连接直方图模式改变信号到色彩提取界面 settings_interface.histogram_mode_changed.connect( self._on_histogram_mode_changed diff --git a/ui/settings.py b/ui/settings.py index bac105f3617fb4215d8eedfc941d34a2118f8a0f..1c53e456c139781cc8828c052239d7852711001e 100644 --- a/ui/settings.py +++ b/ui/settings.py @@ -30,12 +30,14 @@ class SettingsInterface(QWidget): color_sample_count_changed = Signal(int) luminance_sample_count_changed = Signal(int) histogram_scaling_mode_changed = Signal(str) + luminance_histogram_style_changed = Signal(str) color_wheel_mode_changed = Signal(str) histogram_mode_changed = Signal(str) saturation_threshold_changed = Signal(int) brightness_threshold_changed = Signal(int) color_wheel_labels_visible_changed = Signal(bool) gradient_color_space_changed = Signal(str) + gradient_mode_changed = Signal(str) def __init__(self, parent=None): super().__init__(parent) @@ -46,15 +48,18 @@ class SettingsInterface(QWidget): self._color_sample_count = self._config_manager.get('settings.color_sample_count', 5) self._luminance_sample_count = self._config_manager.get('settings.luminance_sample_count', 5) self._histogram_scaling_mode = self._config_manager.get('settings.histogram_scaling_mode', 'linear') + self._luminance_histogram_style = self._config_manager.get('settings.luminance_histogram_style', 'line') self._color_wheel_mode = self._config_manager.get('settings.color_wheel_mode', 'RGB') self._histogram_mode = self._config_manager.get('settings.histogram_mode', 'hue') self._saturation_threshold = self._config_manager.get('settings.saturation_threshold', 70) self._brightness_threshold = self._config_manager.get('settings.brightness_threshold', 70) self._color_wheel_labels_visible = self._config_manager.get('settings.color_wheel_labels_visible', True) self._gradient_color_space = self._config_manager.get('settings.gradient_color_space', 'lab') + self._gradient_mode = self._config_manager.get('settings.gradient_mode', 'gradient') self._language = self._config_manager.get('settings.language', 'ZW_JT') self.setup_ui() self._update_styles() + self._update_color_space_availability(self._gradient_mode) qconfig.themeChangedFinished.connect(self._update_styles) get_locale_manager().language_changed.connect(self._on_language_changed) @@ -136,6 +141,9 @@ class SettingsInterface(QWidget): self.histogram_scaling_card = self._create_histogram_scaling_card() self.histogram_group.addSettingCard(self.histogram_scaling_card) + self.luminance_histogram_style_card = self._create_luminance_histogram_style_card() + self.histogram_group.addSettingCard(self.luminance_histogram_style_card) + self.histogram_mode_card = self._create_histogram_mode_card() self.histogram_group.addSettingCard(self.histogram_mode_card) @@ -187,6 +195,9 @@ class SettingsInterface(QWidget): self.gradient_group = SettingCardGroup(tr('settings.gradient'), self.content_widget) + self.gradient_mode_card = self._create_gradient_mode_card() + self.gradient_group.addSettingCard(self.gradient_mode_card) + self.gradient_color_space_card = self._create_gradient_color_space_card() self.gradient_group.addSettingCard(self.gradient_color_space_card) @@ -325,6 +336,11 @@ class SettingsInterface(QWidget): self.histogram_scaling_card.combo_box.setItemText(0, tr('settings.linear_scaling')) self.histogram_scaling_card.combo_box.setItemText(1, tr('settings.adaptive_scaling')) + self.luminance_histogram_style_card.titleLabel.setText(tr('settings.luminance_histogram_style')) + self.luminance_histogram_style_card.contentLabel.setText(tr('settings.luminance_histogram_style_desc')) + self.luminance_histogram_style_card.combo_box.setItemText(0, tr('settings.luminance_histogram_line')) + self.luminance_histogram_style_card.combo_box.setItemText(1, tr('settings.luminance_histogram_bar')) + self.histogram_mode_card.titleLabel.setText(tr('settings.histogram_mode')) self.histogram_mode_card.contentLabel.setText(tr('settings.histogram_mode_desc')) self.histogram_mode_card.combo_box.setItemText(0, tr('settings.rgb_channel')) @@ -350,11 +366,14 @@ class SettingsInterface(QWidget): # 更新渐变提取卡片 self.gradient_group.titleLabel.setText(tr('settings.gradient')) + self.gradient_mode_card.titleLabel.setText(tr('settings.gradient_mode')) + self.gradient_mode_card.contentLabel.setText(tr('settings.gradient_mode_desc')) + self.gradient_mode_card.combo_box.setItemText(0, tr('settings.gradient_mode_gradient')) + self.gradient_mode_card.combo_box.setItemText(1, tr('settings.gradient_mode_shade')) self.gradient_color_space_card.titleLabel.setText(tr('settings.gradient_color_space')) self.gradient_color_space_card.contentLabel.setText(tr('settings.gradient_color_space_desc')) - self.gradient_color_space_card.combo_box.setItemText(0, tr('settings.gradient_rgb')) - self.gradient_color_space_card.combo_box.setItemText(1, tr('settings.gradient_hsb')) - self.gradient_color_space_card.combo_box.setItemText(2, tr('settings.gradient_lab')) + # 重建颜色空间下拉框(单色模式下无RGB选项) + self._update_color_space_availability(self._gradient_mode) # 更新帮助卡片 self.update_card.titleLabel.setText(tr('settings.version_update')) @@ -551,6 +570,48 @@ class SettingsInterface(QWidget): log_user_action("change_histogram_scaling_mode", {"mode": mode}) self.histogram_scaling_mode_changed.emit(mode) + def _create_luminance_histogram_style_card(self): + """创建明度直方图样式选择卡片""" + card = PushSettingCard( + "", + FluentIcon.PALETTE, + tr('settings.luminance_histogram_style'), + tr('settings.luminance_histogram_style_desc'), + self.content_widget + ) + card.button.setVisible(False) + + combo_box = ComboBox(self.content_widget) + combo_box.addItem(tr('settings.luminance_histogram_line')) + combo_box.setItemData(0, "line") + combo_box.addItem(tr('settings.luminance_histogram_bar')) + combo_box.setItemData(1, "bar") + + for i in range(combo_box.count()): + if combo_box.itemData(i) == self._luminance_histogram_style: + combo_box.setCurrentIndex(i) + break + + combo_box.setFixedWidth(120) + combo_box.currentIndexChanged.connect(self._on_luminance_histogram_style_changed) + + card.hBoxLayout.addWidget(combo_box, 0, Qt.AlignmentFlag.AlignRight) + card.hBoxLayout.addSpacing(16) + + card.combo_box = combo_box + + return card + + def _on_luminance_histogram_style_changed(self, index): + """明度直方图样式改变""" + combo_box = self.luminance_histogram_style_card.combo_box + style = combo_box.itemData(index) + self._luminance_histogram_style = style + self._config_manager.set('settings.luminance_histogram_style', style) + self._config_manager.save() + log_user_action("change_luminance_histogram_style", {"style": style}) + self.luminance_histogram_style_changed.emit(style) + def _create_histogram_mode_card(self): """创建直方图模式选择卡片""" card = PushSettingCard( @@ -635,38 +696,116 @@ class SettingsInterface(QWidget): log_user_action("change_color_wheel_mode", {"mode": mode}) self.color_wheel_mode_changed.emit(mode) - def _create_gradient_color_space_card(self): - """创建渐变颜色空间选择卡片""" + def _create_gradient_mode_card(self): + """创建渐变模式选择卡片""" card = PushSettingCard( "", FluentIcon.PALETTE, - tr('settings.gradient_color_space'), - tr('settings.gradient_color_space_desc'), + tr('settings.gradient_mode'), + tr('settings.gradient_mode_desc'), self.content_widget ) card.button.setVisible(False) combo_box = ComboBox(self.content_widget) - combo_box.addItem(tr('settings.gradient_rgb')) - combo_box.setItemData(0, "rgb") + combo_box.addItem(tr('settings.gradient_mode_gradient')) + combo_box.setItemData(0, "gradient") + combo_box.addItem(tr('settings.gradient_mode_shade')) + combo_box.setItemData(1, "shade") + + for i in range(combo_box.count()): + if combo_box.itemData(i) == self._gradient_mode: + combo_box.setCurrentIndex(i) + break + + combo_box.setFixedWidth(120) + combo_box.currentIndexChanged.connect(self._on_gradient_mode_changed) + + card.hBoxLayout.addWidget(combo_box, 0, Qt.AlignmentFlag.AlignRight) + card.hBoxLayout.addSpacing(16) + + card.combo_box = combo_box + + return card + + def _on_gradient_mode_changed(self, index): + """渐变模式改变""" + combo_box = self.gradient_mode_card.combo_box + mode = combo_box.itemData(index) + self._gradient_mode = mode + self._config_manager.set('settings.gradient_mode', mode) + self._config_manager.save() + log_user_action("change_gradient_mode", {"mode": mode}) + + # 单色明度梯度模式下禁用RGB选项 + self._update_color_space_availability(mode) + + self.gradient_mode_changed.emit(mode) + + def _update_color_space_availability(self, gradient_mode: str): + """根据渐变模式更新颜色空间选项可用性 + + 单色明度梯度模式下,RGB插值不适用(无法固定色相和饱和度) + + Args: + gradient_mode: 渐变模式 ('gradient' 或 'shade') + """ + combo_box = self.gradient_color_space_card.combo_box + is_shade = gradient_mode == 'shade' + + # 如果当前选中的是RGB且切换到单色模式,自动切换为HSB + if is_shade and self._gradient_color_space == 'rgb': + self._gradient_color_space = 'hsb' + self._config_manager.set('settings.gradient_color_space', 'hsb') + self._config_manager.save() + self.gradient_color_space_changed.emit('hsb') + + # 重建下拉框选项 + current_data = self._gradient_color_space + combo_box.blockSignals(True) + combo_box.clear() + + if not is_shade: + combo_box.addItem(tr('settings.gradient_rgb')) + combo_box.setItemData(combo_box.count() - 1, "rgb") + combo_box.addItem(tr('settings.gradient_hsb')) - combo_box.setItemData(1, "hsb") + combo_box.setItemData(combo_box.count() - 1, "hsb") + + combo_box.addItem(tr('settings.gradient_hsl')) + combo_box.setItemData(combo_box.count() - 1, "hsl") + combo_box.addItem(tr('settings.gradient_lab')) - combo_box.setItemData(2, "lab") + combo_box.setItemData(combo_box.count() - 1, "lab") + # 恢复选中项 for i in range(combo_box.count()): - if combo_box.itemData(i) == self._gradient_color_space: + if combo_box.itemData(i) == current_data: combo_box.setCurrentIndex(i) break + combo_box.blockSignals(False) + + def _create_gradient_color_space_card(self): + """创建渐变颜色空间选择卡片""" + card = PushSettingCard( + "", + FluentIcon.PALETTE, + tr('settings.gradient_color_space'), + tr('settings.gradient_color_space_desc'), + self.content_widget + ) + card.button.setVisible(False) + + combo_box = ComboBox(self.content_widget) + # 初始选项由 _update_color_space_availability 统一管理 + card.combo_box = combo_box combo_box.setFixedWidth(120) combo_box.currentIndexChanged.connect(self._on_gradient_color_space_changed) card.hBoxLayout.addWidget(combo_box, 0, Qt.AlignmentFlag.AlignRight) card.hBoxLayout.addSpacing(16) - card.combo_box = combo_box - return card def _on_gradient_color_space_changed(self, index): @@ -679,6 +818,20 @@ class SettingsInterface(QWidget): log_user_action("change_gradient_color_space", {"color_space": mode}) self.gradient_color_space_changed.emit(mode) + def set_gradient_mode(self, mode): + """设置渐变模式 + + Args: + mode: 'gradient' 或 'shade' + """ + self._gradient_mode = mode + if hasattr(self.gradient_mode_card, 'combo_box'): + combo_box = self.gradient_mode_card.combo_box + for i in range(combo_box.count()): + if combo_box.itemData(i) == mode: + combo_box.setCurrentIndex(i) + break + def get_gradient_color_space(self): """获取当前渐变颜色空间""" return self._gradient_color_space diff --git a/version.py b/version.py index 1934ce8648ef7e26763c1d4e7389a146be23d05c..6f502b5cb92d217dfd5f4df9d3641fbf8ee85541 100644 --- a/version.py +++ b/version.py @@ -8,8 +8,8 @@ class VersionManager: """初始化版本管理器""" # 版本号组件 self.major: int = 1 - self.minor: int = 7 - self.patch: int = 1 + self.minor: int = 8 + self.patch: int = 0 self.build: int = 0 self.prerelease: str = "" diff --git a/version.txt b/version.txt index ca466dcf3a997845b0197e39c26ad3448be12777..5036dfc9966fad9613c220afec52b45713458a36 100644 --- a/version.txt +++ b/version.txt @@ -1,6 +1,6 @@ -1.7.1 -2026.4.12.1 -1.7.1.0 +1.8.0 +2026.4.19.1 +1.8.0.0 浮晓 HXiao Studio © 2026 浮晓 HXiao Studio 取色卡 - Color Card \ No newline at end of file diff --git a/version_info.txt b/version_info.txt index 5231f753ae253d298d52055d4dcaa7a4f19146b2..38886cb410d72b82a554c3d480943aa8e0b533b9 100644 --- a/version_info.txt +++ b/version_info.txt @@ -1,7 +1,7 @@ VSVersionInfo( ffi=FixedFileInfo( - filevers=(2026,4,12,1), - prodvers=(1,7,1,0), + filevers=(2026,4,19,1), + prodvers=(1,8,0,0), mask=0x3f, flags=0x0, OS=0x4, @@ -17,12 +17,12 @@ VSVersionInfo( [ StringStruct(u'CompanyName', u'浮晓 HXiao Studio'), StringStruct(u'FileDescription', u'取色卡 - Color Card'), - StringStruct(u'FileVersion', u'1.7.1'), + StringStruct(u'FileVersion', u'1.8.0'), StringStruct(u'InternalName', u'Color_Card'), StringStruct(u'LegalCopyright', u'© 2026 浮晓 HXiao Studio'), StringStruct(u'OriginalFilename', u'Color_Card.exe'), StringStruct(u'ProductName', u'取色卡'), - StringStruct(u'ProductVersion', u'1.7.1'), + StringStruct(u'ProductVersion', u'1.8.0'), StringStruct(u'Comments', u'一站式的图片的图片分析和配色工具') ] ) diff --git a/website/index.html b/website/index.html index fe114e56c693a16b6660b45566d53179d3c27819..0c2f547043294611fc2b426e2ba96d7b21943282 100644 --- a/website/index.html +++ b/website/index.html @@ -618,7 +618,7 @@ 渐变生成

渐变生成

-

生成渐变色序列,支持多种颜色空间

+

双色渐变与单色明度梯度,支持多种颜色空间

@@ -1261,7 +1261,7 @@ { icon: 'library', title: '内置色彩库', desc: '集成 Open Color、Tailwind CSS、Material Design 等13大开源配色方案,总计661组色卡' }, { icon: 'eye', title: '配色预览', desc: '支持手机UI、网页、插画、排版、品牌、海报、图案、杂志等8种场景预览,支持自定义SVG' }, { icon: 'barchart', title: '明度分析', desc: '将图片按明度分为9个区域,提供直方图可视化,辅助调色决策' }, - { icon: 'gradient', title: '渐变生成', desc: '选择起始和结束颜色,生成渐变色序列,支持RGB/HSB/LAB三种颜色空间插值,可调节1-10个中间色' }, + { icon: 'gradient', title: '渐变生成', desc: '支持双色渐变和单色明度梯度两种模式,RGB/HSB/HSL/LAB四种颜色空间插值,可调节中间色数量' }, { icon: 'globe', title: '多语言支持', desc: '支持简体中文、繁体中文、英语、日语、法语、俄语六种语言界面切换,支持跟随系统语言自动切换' }, { icon: 'moon', title: '明暗主题', desc: '支持深色模式和浅色模式切换,保护视力,适应不同使用环境' }, ]; diff --git a/website/public/changelog.json b/website/public/changelog.json index a5c281f9b1a21a42fa7d3038aeaf7ad1913497e1..2b1b94b2c95681d8f7c5af6c82485d885d15d2ad 100644 --- a/website/public/changelog.json +++ b/website/public/changelog.json @@ -1,5 +1,51 @@ { "versions": [ + { + "version": "v1.8.0", + "date": "2026-04-19", + "changes": [ + { + "category": "新增功能", + "items": [ + { + "title": "渐变提取增强", + "desc": "新增单色明度梯度模式,渐变提取支持HSL颜色空间插值" + }, + { + "title": "主题系统", + "desc": "主题切换按钮增加跟随系统状态" + }, + { + "title": "明度直方图", + "desc": "支持线连接和柱状图两种样式切换" + } + ] + }, + { + "category": "问题修复", + "items": [ + "修正明度区域8-9明度遮罩未覆盖纯白色像素的问题", + "配置文件加载失败时使用默认配置" + ] + }, + { + "category": "界面优化", + "items": [ + "统一明度提取和色彩提取面板的提示文字字体样式", + "调整渐变提取界面颜色圆点样式", + "统一场景SVG尺寸、文字颜色并优化元素属性、布局", + "修复部分系统配色预览区域间隔显示灰条问题" + ] + }, + { + "category": "内容调整", + "items": [ + "新增大量SVG场景", + "启用配色预览混合布局并设为默认" + ] + } + ] + }, { "version": "v1.7.1", "date": "2026-04-12", diff --git "a/\346\226\207\346\241\243/\345\274\200\345\217\221\350\247\204\350\214\203.md" "b/\346\226\207\346\241\243/\345\274\200\345\217\221\350\247\204\350\214\203.md" index f3ca6265b4611682fd1d39aed7c2869d6fed7006..711a2dd3b0c54ba544960ae323d7cabbdf8b277e 100644 --- "a/\346\226\207\346\241\243/\345\274\200\345\217\221\350\247\204\350\214\203.md" +++ "b/\346\226\207\346\241\243/\345\274\200\345\217\221\350\247\204\350\214\203.md" @@ -36,6 +36,7 @@ color_card/ │ ├── app_mode.py # 应用运行模式检测模块(安装版/便携版检测、配置目录获取) │ ├── async_loader.py # 异步加载基类模块(BaseBatchLoader) │ ├── color.py # 颜色处理模块(颜色转换、明度计算、配色生成算法) +│ ├── gradient.py # 渐变生成模块(双色渐变插值、单色明度梯度生成) │ ├── colorblind.py # 色盲模拟模块(色盲类型定义、LMS色彩空间转换、色盲模拟算法) │ ├── color_data.py # 颜色数据管理模块(延迟加载各颜色库数据) │ ├── color_service.py # 颜色服务模块(ColorService、DominantColorExtractor,业务层颜色提取服务) @@ -1263,26 +1264,9 @@ for i, color in enumerate(colors): *** -## 11. 交互设计规范 +## 11. 版本管理规范 -### 11.1 取色点交互 - -- 鼠标悬停:显示手型光标 -- 拖动时:实时更新颜色值 -- 边界限制:限制在图片显示区域内 - -### 11.2 快捷键规范 - -| 快捷键 | 功能 | -| :------: | :--: | -| Ctrl + O | 打开图片 | -| Ctrl + Q | 退出程序 | - -*** - -## 12. 版本管理规范 - -### 12.1 版本号格式 +### 11.1 版本号格式 - 格式:`主版本.次版本.修订版本` - 示例:`1.0.0` @@ -1290,7 +1274,7 @@ for i, color in enumerate(colors): - 次版本:新增功能 - 修订版本:bug 修复 -### 12.2 提交信息规范 +### 11.2 提交信息规范 **格式:** `[类型] 详细描述` @@ -1316,9 +1300,9 @@ for i, color in enumerate(colors): *** -## 13. 更新日志格式规范 +## 12. 更新日志格式规范 -### 13.1 版本格式 +### 12.1 版本格式 ```markdown # 🎨 取色卡 v{主版本}.{次版本} 更新日志 @@ -1337,7 +1321,7 @@ for i, color in enumerate(colors): - {优化描述} ``` -### 13.2 分类说明 +### 12.2 分类说明 | 分类 | Emoji | 说明 | | :--: | :---: | :-------- | @@ -1349,13 +1333,13 @@ for i, color in enumerate(colors): **注意:** 分类可根据实际更新内容灵活调整,只需保持格式正确(`## Emoji 分类名称`)即可。 -### 13.3 内容规范 +### 12.3 内容规范 - **功能模块分组**:将相关功能按模块分组,使用粗体标注模块名称 - **表述规范**:使用动词开头(新增、修复、优化、调整、重构),描述简洁清晰 - **条目排序**:同一分类内按重要性排序 -### 13.4 示例 +### 12.4 示例 ```markdown # 🎨 取色卡 v1.2 更新日志 @@ -1382,16 +1366,16 @@ for i, color in enumerate(colors): *** -## 14. 配置管理规范 +## 13. 配置管理规范 -### 14.1 配置管理模块 +### 13.1 配置管理模块 使用 `core/config.py` 统一管理应用程序状态。 - 配置文件:JSON 格式,存储在用户主目录下的 `.color_card/config.json` - 使用单例模式获取全局配置管理器实例 -### 14.2 配置项说明 +### 13.2 配置项说明 | 配置键 | 类型 | 默认值 | 说明 | | :---------------------------: | :----: | :-------------: | :------------------------- | @@ -1405,7 +1389,7 @@ for i, color in enumerate(colors): | `window.is_fullscreen` | bool | false | 窗口是否全屏 | | `favorites` | list | \[] | 收藏的配色列表 | -### 14.3 使用示例 +### 13.3 使用示例 ```python from core import get_config_manager @@ -1418,9 +1402,9 @@ config_manager.save() *** -## 15. 项目官网维护规范 +## 14. 项目官网维护规范 -### 15.1 官网结构 +### 14.1 官网结构 **官网地址:** @@ -1443,7 +1427,7 @@ website/ # 官网开发目录 └── ... ``` -### 15.2 更新日志维护 +### 14.2 更新日志维护 **配置文件:** `docs/changelog.json` 和 `website/public/changelog.json` @@ -1476,7 +1460,7 @@ website/ # 官网开发目录 **维护要求:** 发布新版本时同步更新 `changelog.json`;保持两个文件同步(docs 和 website/public);分类名称与第13章更新日志分类保持一致。 -### 15.3 截图更新 +### 14.3 截图更新 **截图存放位置:** `docs/screenshots/` 和 `website/public/screenshots/` @@ -1484,7 +1468,7 @@ website/ # 官网开发目录 **更新步骤:** 替换 `website/public/screenshots/` 中的图片;同步复制到 `docs/screenshots/`;刷新网页查看效果。 -### 15.4 部署流程 +### 14.4 部署流程 **自动部署:** 推送代码到 GitHub 后自动触发 GitHub Actions 部署;部署源:`docs/` 目录 @@ -1495,7 +1479,7 @@ Copy-Item website\public\changelog.json docs\changelog.json -Force Copy-Item website\public\screenshots\* docs\screenshots\ -Force ``` -### 15.5 注意事项 +### 14.5 注意事项 - JSON 文件中避免使用中文引号 - 截图文件不要过大,建议压缩后上传 @@ -1504,9 +1488,9 @@ Copy-Item website\public\screenshots\* docs\screenshots\ -Force *** -## 16. 多语言国际化规范 +## 15. 多语言国际化规范 -### 16.1 模块概述 +### 15.1 模块概述 多语言国际化功能由 `utils/locale.py` 模块提供,支持应用程序的多语言切换。 @@ -1519,7 +1503,7 @@ Copy-Item website\public\screenshots\* docs\screenshots\ -Force | `set_language()` | 语言切换函数 | | `get_locale_manager()` | 获取全局语言管理器实例 | -### 16.2 语言包结构 +### 15.2 语言包结构 语言包存放在 `locales/` 目录,使用 TOML 格式。 @@ -1537,7 +1521,7 @@ title = "已复制" content = "颜色值已复制到剪贴板" ``` -### 16.3 使用方法 +### 15.3 使用方法 **基本翻译:** @@ -1562,7 +1546,7 @@ set_language('EN_US') get_locale_manager().language_changed.connect(self._on_language_changed) ``` -### 16.4 界面国际化规范 +### 15.4 界面国际化规范 ```python class MyInterface(QWidget): @@ -1599,9 +1583,9 @@ class MyInterface(QWidget): *** -## 17. 日志系统规范 +## 16. 日志系统规范 -### 17.1 日志系统概述 +### 16.1 日志系统概述 项目使用统一的日志系统,用于问题排查、行为追踪、性能监控和运行监控。 @@ -1614,7 +1598,7 @@ class MyInterface(QWidget): | `log_user_action()` | `core/logger.py` | 记录用户操作 | | `log_performance()` | `core/logger.py` | 记录性能数据 | -### 17.2 日志配置 +### 16.2 日志配置 **存储位置:** 日志存储在配置目录下的 `logs/` 子目录,路径:`~/.color_card/logs/` @@ -1622,7 +1606,7 @@ class MyInterface(QWidget): **清理策略:** 保留最近 30 天的日志文件;启动时自动清理过期日志 -### 17.3 日志级别定义 +### 16.3 日志级别定义 | 级别 | 用途 | 示例 | | :--------: | :------ | :------------------- | @@ -1632,7 +1616,7 @@ class MyInterface(QWidget): | `ERROR` | 需要关注的问题 | 保存失败、解析错误、服务初始化失败 | | `CRITICAL` | 致命错误 | 程序无法继续运行 | -### 17.4 日志格式 +### 16.4 日志格式 ```text [时间] [级别] [模块名] 消息内容 @@ -1644,7 +1628,7 @@ class MyInterface(QWidget): [2026-02-28 14:30:30] [ERROR] [image_service] 图片加载失败: path=invalid.jpg, error=文件不存在 ``` -### 17.5 使用方法 +### 16.5 使用方法 **模块级日志记录:** @@ -1682,7 +1666,7 @@ with log_performance("generate_scheme", {"type": scheme_type}): return _do_generate_scheme(base_hue, scheme_type) ``` -### 17.6 必须记录的场景 +### 16.6 必须记录的场景 **系统事件:** 程序启动/退出;配置加载/保存;主题切换;语言切换 @@ -1690,7 +1674,7 @@ with log_performance("generate_scheme", {"type": scheme_type}): **错误和异常:** 文件操作失败;图片解析错误;配置读写错误;服务初始化失败 -### 17.7 禁止直接使用 print 输出 +### 16.7 禁止直接使用 print 输出 **核心原则:禁止在业务代码中直接使用 `print()` 输出调试信息** @@ -1715,7 +1699,7 @@ logger.info(f"加载完成: {count} 个场景") - 临时调试脚本可以使用 `print()` - 命令行工具的主程序可以使用 `print()` 输出结果 -### 17.8 AI辅助调试 +### 16.8 AI辅助调试 **日志查看流程:** 应用程序启动失败时,查看控制台输出定位问题;功能执行出现异常时,分析错误信息;结合代码上下文,理解错误原因;根据日志信息制定修复方案。 @@ -1723,16 +1707,16 @@ logger.info(f"加载完成: {count} 个场景") *** -## 18. 重构规范 +## 17. 重构规范 -### 18.1 重构原则 +### 17.1 重构原则 1. **保持功能不变**:重构过程中不改变现有功能 2. **渐进式重构**:分阶段进行,每阶段可独立验证 3. **先整理后重构**:先规范现有代码,再提取基类,最后重组目录 4. **代码清理同步**:修改代码时同步清理相关重复代码 -### 18.2 基类提取规范 +### 17.2 基类提取规范 **步骤:** 分析相似组件的公共逻辑;设计基类接口(抽象方法);迁移第一个子类,验证基类设计;迁移其他子类;全面测试验证。 @@ -1749,7 +1733,7 @@ class ImageCanvas(BaseCanvas): # 具体实现... ``` -### 18.3 模块合并规范 +### 17.3 模块合并规范 **合并原则:** 将紧密相关的类合并到同一文件;避免过度拆分,提高代码可维护性;保持模块化,但减少文件数量。 @@ -1757,7 +1741,7 @@ class ImageCanvas(BaseCanvas): *** -## 19. 开发经验总结 +## 18. 开发经验总结 > **详细内容请参阅**:[开发经验总结.md](开发经验总结.md) @@ -1773,9 +1757,9 @@ class ImageCanvas(BaseCanvas): *** -## 20. 测试规范 +## 19. 测试规范 -### 20.1 测试目录结构 +### 19.1 测试目录结构 ```text color_card/ @@ -1787,7 +1771,7 @@ color_card/ └── ... ``` -### 20.2 测试框架配置 +### 19.2 测试框架配置 **pytest.ini 配置:** @@ -1809,7 +1793,7 @@ markers = ui: UI 测试 ``` -### 20.3 开发依赖 +### 19.3 开发依赖 **tests/requirements-dev.txt:** @@ -1829,7 +1813,7 @@ pytest-qt>=4.0.0 pip install -r tests/requirements-dev.txt ``` -### 20.4 测试命名规范 +### 19.4 测试命名规范 | 类型 | 命名规则 | 示例 | | ---- | ----------- | ---------------------------- | @@ -1837,7 +1821,7 @@ pip install -r tests/requirements-dev.txt | 测试类 | `Test*` | `TestHistogramCalculator` | | 测试方法 | `test_*` | `test_cancel_does_not_block` | -### 20.5 测试分类标记 +### 19.5 测试分类标记 使用 pytest marker 标记测试类型: @@ -1860,7 +1844,7 @@ python -m pytest -m unit # 只运行单元测试 python -m pytest -m "not slow" # 跳过慢速测试 ``` -### 20.6 Qt 测试规范 +### 19.6 Qt 测试规范 **使用 pytest-qt:** pytest-qt 提供了 `qtbot` fixture 用于 Qt 组件测试。 @@ -1881,7 +1865,7 @@ def test_async_calculation(qtbot): assert len(blocker.args[0]) == 256 ``` -### 20.7 线程安全测试 +### 19.7 线程安全测试 ```python def test_cancel_does_not_block(qtbot): @@ -1898,7 +1882,7 @@ def test_cancel_does_not_block(qtbot): calculator.wait(1000) ``` -### 20.8 运行测试 +### 19.8 运行测试 ```bash python -m pytest # 运行所有测试 @@ -1907,7 +1891,7 @@ python -m pytest -x # 在第一个失败时停止 python -m pytest --cov=core --cov-report=html # 生成覆盖率报告 ``` -### 20.9 测试最佳实践 +### 19.9 测试最佳实践 1. **测试独立性**:每个测试应该独立运行,不依赖其他测试 2. **测试可重复性**:相同输入应该产生相同结果 @@ -1917,9 +1901,9 @@ python -m pytest --cov=core --cov-report=html # 生成覆盖率报告 *** -## 21. 开源许可证管理规范 +## 20. 开源许可证管理规范 -### 21.1 许可证管理概述 +### 20.1 许可证管理概述 本项目采用 **GPLv3** 作为主许可证,使用了多个第三方库和开发工具,每个都有其自己的开源许可证。完整的许可证管理是开源项目合规性的重要组成部分。 @@ -1941,14 +1925,14 @@ python -m pytest --cov=core --cov-report=html # 生成覆盖率报告 | 工具链 | GPLv2+ | UPX | | 工具链 | Modified BSD | Inno Setup | -### 21.2 许可证文件管理 +### 20.2 许可证文件管理 **必须维护的许可证文件:** 1. **LICENSE** - 主许可证文本文件:包含完整的 GPLv3 许可证文本;包含所有第三方库的完整许可证信息;包含开发工具链的完整许可证信息 2. **file/LICENSE.html** - HTML 格式的许可证文件:用于应用程序内显示;与文本版 LICENSE 内容保持一致 -### 21.3 第三方库许可证信息收集规范 +### 20.3 第三方库许可证信息收集规范 **收集内容清单:** @@ -1962,7 +1946,7 @@ python -m pytest --cov=core --cov-report=html # 生成覆盖率报告 **收集渠道:** 官方 GitHub 仓库的 LICENSE 文件;官方网站许可证页面;PyPI 项目页面的元数据;源码包中的 LICENSE 文件。 -### 21.4 许可证文本格式规范 +### 20.4 许可证文本格式规范 **文本版 LICENSE 格式:** @@ -1984,7 +1968,7 @@ python -m pytest --cov=core --cov-report=html # 生成覆盖率报告 **格式要求:** 使用 `====`(80个字符)作为章节分隔线;使用 `----`(80个字符)作为子章节分隔线;每个库独立成节,编号排序;许可证文本保持原始格式。 -### 21.5 关于窗口许可证显示规范 +### 20.5 关于窗口许可证显示规范 **关于对话框必须包含的信息:** @@ -2006,7 +1990,7 @@ def _get_about_text(self): **显示要求:** 每个库必须包含:版权所有、许可证类型、项目地址;按类别分组(开源项目、开发工具链);格式统一,便于阅读。 -### 21.6 许可证兼容性检查 +### 20.6 许可证兼容性检查 **兼容性原则:** @@ -2016,7 +2000,7 @@ def _get_about_text(self): **检查清单:** 所有第三方许可证与 GPLv3 兼容;所有许可证文本完整且最新;所有版权信息准确无误;所有项目链接可访问。 -### 21.7 许可证更新流程 +### 20.7 许可证更新流程 **新增第三方库时的步骤:** @@ -2025,7 +2009,7 @@ def _get_about_text(self): 3. **文件更新**:更新 LICENSE 文本文件;更新 file/LICENSE.html;更新关于窗口的许可证显示 4. **验证测试**:检查文本格式是否正确;验证链接可访问性;确认所有文件内容一致 -### 21.8 常见许可证文本获取地址 +### 20.8 常见许可证文本获取地址 | 许可证 | 官方地址 | | :----------: | :------------------------------------------------ | @@ -2035,7 +2019,7 @@ def _get_about_text(self): | Apache-2.0 | | | BSD-3-Clause | | -### 21.9 注意事项 +### 20.9 注意事项 **必须避免的问题:** @@ -2047,18 +2031,20 @@ def _get_about_text(self): *** -## 22. 附录 +## 21. 附录 -### 22.1 规范维护 +### 21.1 规范维护 **本规范将根据项目发展进行更新,以适应新的功能需求和技术变化。** -### 22.2 更新记录 +### 21.2 更新记录 **(变更内容填写对开发规范的内容更新,而不是对代码调整的详细记录)** | 版本 | 日期 | 变更内容 | | :--: | :--------: | :------------------------------------------------------------------------: | +| 3.50 | 2026-04-13 | 更新项目结构(1.3节):新增 gradient.py 到 core/ 目录,包含双色渐变插值和单色明度梯度生成功能 | +| 3.49 | 2026-04-12 | 删除第11章交互设计规范(含快捷键规范);更新后续章节编号(12-22章改为11-21章) | | 3.47 | 2026-03-29 | 更新多语言国际化规范(16.2节):语言包格式从 JSON 迁移到 TOML,使用 Python 3.11+ 内置 tomllib 模块 | | 3.46 | 2026-03-27 | 更新项目结构(1.3节):新增 app_mode.py 到 core/ 目录,支持安装版/便携版运行模式检测和配置目录区分 | | 3.45 | 2026-03-24 | 更新项目结构(1.3节):新增 confirm_dialogs.py 到 dialogs/ 目录,包含导入模式和删除确认对话框 |