geopro/src/app/Theme.hpp

143 lines
7.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
// 全局视觉主题浅色专业方向Fusion 风格 + 浅色 QPalette + 结构化 QSS。
// 仅外观——不改任何信号槽 / 渲染 / 数据逻辑。在 QApplication 构造后、弹登录窗前调用一次。
//
// 设计令牌(与登录窗、视图详情浮层共享,保证全项目一脉相承):
// 外壳底 #F4F6FA 面板白 #FFFFFF 抬升/表头 #EDF1F7
// 强调 #2D6CB5 悬停 #2862A6 按下 #234F87 选中行 #DCE9F8
// 文字 #1F2A3D 次要文字 #5A6B85 边框 #D5DBE5 强边框 #C2CCDA
// 危险 #C0392B
#include <QColor>
#include <QObject>
#include <QString>
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.18body→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/b01
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