#pragma once // 全局视觉主题(浅色专业方向):Fusion 风格 + 浅色 QPalette + 结构化 QSS。 // 仅外观——不改任何信号槽 / 渲染 / 数据逻辑。在 QApplication 构造后、弹登录窗前调用一次。 // // 设计令牌(与登录窗、视图详情浮层共享,保证全项目一脉相承): // 外壳底 #F4F6FA 面板白 #FFFFFF 抬升/表头 #EDF1F7 // 强调 #2D6CB5 悬停 #2862A6 按下 #234F87 选中行 #DCE9F8 // 文字 #1F2A3D 次要文字 #5A6B85 边框 #D5DBE5 强边框 #C2CCDA // 危险 #C0392B #include #include #include class QApplication; class QWidget; namespace geopro::app { // 主题管理器(纯 Qt,替代 ElaTheme):持有当前明暗 + 是否跟随系统;切换发 changed() 信号, // 全 UI(全局 QSS 由 main 重应用、内联 chrome 由 applyTokenizedStyleSheet)据此热切重着色。 class ThemeManager : public QObject { Q_OBJECT public: static ThemeManager& instance(); bool isDark() const { return dark_; } void setMode(const QString& mode); // "system"|"light"|"dark":持久化 + 应用 + 发 changed void applyPersisted(); // 按持久化偏好设置状态(系统模式则取系统明暗) signals: void changed(); private: explicit ThemeManager(QObject* parent = nullptr); bool dark_ = false; bool follow_ = true; }; // ── 排版令牌(全项目唯一字号阶 + 字重角色)────────────────────────── // 各处 QSS 的 font-size / font-weight 一律引用这些值,不再散落硬编码 px。 // 阶比 ~1.18(body→title→heading),刻意拉开层级——避免 11/12/13/14 // 这类只差 1px 的"糊层级",让标题/正文/说明三档一眼可分。 // 单位:px(与全局 px 化的 QSS、固定像素行高对齐;后续若做无障碍字号 // 缩放再统一切 pt)。字重:400 正文 / 500 可交互激活 / // 600 标签·标题 / 700 仅展示性大标题。 namespace type { inline constexpr int kCaption = 12; // 徽标·提示·角色名·错误·副标题·字段标签 inline constexpr int kBody = 13; // 树/列表/菜单/正文(= 全局基准字号) inline constexpr int kLabel = 13; // 表头·用户名等需加粗的同级标签(配 600) inline constexpr int kTitle = 15; // 面板/停靠区/区段标题·主操作按钮 inline constexpr int kHeading = 18; // 视图/对话框级标题(预留) inline constexpr int kDisplay = 24; // 登录品牌名(唯一展示性大字) inline constexpr int kWeightRegular = 400; inline constexpr int kWeightMedium = 500; inline constexpr int kWeightSemibold = 600; inline constexpr int kWeightBold = 700; } // namespace type // ── 间距令牌(全项目唯一间距阶)────────────────────────────────── // 取代散落的 5/7/9/11/13/15/26 等任意值。这是密集专业工具的实际节奏 // (非外加的 8pt 网格):相邻档 2px 粒度,足够紧凑又不糊成一片。 // 用法:布局 setContentsMargins/setSpacing/addSpacing 与 QSS padding/margin // 一律引用这些档;明显的奇数值就近归档(13/15→lg, 11→ml, 26→xxl)。 namespace space { inline constexpr int kXxs = 2; // 发丝级:下划线偏移、滚动条边距 inline constexpr int kXs = 4; // 紧凑内边距、最小间隙 inline constexpr int kSm = 6; // 行内紧凑(控件竖向 padding) inline constexpr int kMd = 8; // 标准间隔(最常用) inline constexpr int kMl = 10; // 偏大行距(密集行/验证码行) inline constexpr int kLg = 12; // 分组间隔、面板内左右边距 inline constexpr int kXl = 16; // 区块内边距 inline constexpr int kXxl = 24; // 区块间距、表单纵向边距 inline constexpr int kXxxl = 32; // 页面级留白(登录窗左右边距) } // namespace space // ── 圆角令牌(统一原先 4/5/6/7/8/9 共 6 档为 3 档)──────────────── // 圆形元素(头像等)用 直径/2 单独写字面量,不入档。 namespace radius { inline constexpr int kSm = 6; // 按钮·输入·菜单项·滚动条·进度条 inline constexpr int kMd = 8; // 卡片·面板·对话框·菜单·分组框 inline constexpr int kPill = 9; // 数量徽标胶囊 } // namespace radius // ── 语义色令牌(状态/反馈,产品语境:只在承载含义处用,不作装饰)────────── // 文字值均针对白底面板(#FFFFFF)选深色,对比度 ≥4.5:1(正文级);与冷调中性 // 调色板调和。danger 沿用既有红,避免引入第二种红。 namespace semantic { inline constexpr const char* kInfo = "#2D6CB5"; // 信息·进行中(= 品牌蓝) inline constexpr const char* kSuccess = "#15803D"; // 成功·已完成(深绿) inline constexpr const char* kWarning = "#B45309"; // 警告·需注意(深琥珀) inline constexpr const char* kDanger = "#C0392B"; // 危险·错误(沿用既有红) // 浅色填充(徽标/标签底色,配同族深色文字使用)。 inline constexpr const char* kWarningFill = "#FBEAD2"; // 警告底纹(配 kWarning 文字) } // namespace semantic // 应用专业主题(Fusion + 调色板 + 全局样式表)。dark=true 走暗色(P2 主题桥用)。 // 暗色复用同一 QSS 结构,颜色全由 kTokens 双值(fillTokens/tokenHex)驱动;幂等,可随主题切换重复调用。 void applyThemeMode(QApplication& app, bool dark); // 浅色主题快捷入口(= applyThemeMode(app,false))。经典壳启动调用一次。 void applyTheme(QApplication& app); // ── 设置:主题 / 界面字号 偏好(QSettings 持久化)──────────────────────── // 启动时(eApp->init + applyBrandAccent 之后、弹登录窗之前)各调一次,使登录页与主页统一。 void applyPersistedThemeMode(); // 应用持久化主题:跟随系统 / 浅色 / 深色 → ElaTheme void applyPersistedFontScale(); // 应用持久化字号:设 qApp 基准字体 + 记录缩放(供 scaledPx) QString themeModePreference(); // "system" | "light" | "dark"(默认 system) void setThemeModePreference(const QString& mode); // 持久化 + 立即应用(主题可热切) int fontScalePreference(); // 缩放百分比 90/100/115/130(默认 100) void setFontScalePreference(int percent); // 仅持久化(字号改动重启后生效) int scaledPx(int basePx); // basePx × 当前字号% / 100(内联 QSS 字号用,使自定义 chrome 也随字号缩放) // 当前 ElaTheme 是否暗色(供内联样式判断)。 bool isDarkTheme(); // VTK 渲染器背景色(随当前主题,取 ElaTheme 窗口底色)。写入 r/g/b(0–1)。 void vtkBackground(double& r, double& g, double& b); // ── 语义令牌(单一事实来源,取值见 Theme.cpp kTokens;规范 §1.5 + 附录 A + §1.3)── // 组件只引语义 token,禁止散落硬编码 hex。token 名形如 "bg/panel"、"accent/primary"。 QString token(const char* name); // 当前明暗下的 hex(未知名返回品红 "#FF00FF" 以便一眼发现漏配) QColor tokenColor(const char* name); // 同上,QColor 形式 // 把 QSS 模板里的 {{token}} 占位替换为当前明暗的 hex 后返回。 QString fillTokens(const QString& tmpl); // 应用一段 {{token}} 模板 QSS 到 widget,并随主题切换自动重填。 void applyTokenizedStyleSheet(QWidget* w, const QString& tmpl); } // namespace geopro::app