geopro/src/app/Theme.hpp

143 lines
7.9 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 构造后、弹登录窗前调用一次。
//
// 设计令牌唯一事实来源 = Theme.cpp 的 kTokens 表(规范 §1.5)。组件只引语义 token
// token()/{{token}}),禁止在此散落硬编码 hex。速查bg/app #F7F8FA · accent/primary
// #3B73EC · text/primary #272C35 · border/default #E3E6EB · status/danger #E5484D。
#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;
// 等宽字族(规范 §2.1):坐标/数值/编号/深度刻度用,保证逐列对齐。
// 仅在此暴露,组件阶段(数值/坐标/ID 标签)按需引用,不在全局 QSS 强加。
inline constexpr const char* kMonoFamily = "Cascadia Code, JetBrains Mono, Consolas, monospace";
} // 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; // 页面级留白(登录窗左右边距)
// 可编辑表单标签列宽(规范 §7.0.2:固定 100px同表单内等宽对齐右标签
// 唯一事实来源——DynamicFormEditor / 各参数对话框经 formkit::editLabel 统一引此值。
inline constexpr int kFormLabelCol = 100;
// 只读键值表§6.4)键列定宽。与可编辑标签列分档(只读两列布局更紧凑)——
// 唯一事实来源DynamicFormView 引此值;规范 §7.0.10 列为精确常量,禁止区间/魔数。
inline constexpr int kDetailKeyCol = 72;
// 可编辑字段最大宽(规范 §7.0.2:宽对话框中「不要拉满」,单字段最大约 360px
// 窄属性面板里该上限大于面板宽,故字段仍填满——符合规范。多行/长文本不受此限。
inline constexpr int kFormFieldMax = 360;
} // namespace space
// ── 圆角令牌(规范 §3.2)────────────────────────────────────────
// 圆形元素(头像等)用 直径/2 单独写字面量,不入档。
namespace radius {
inline constexpr int kSm = 4; // 按钮·输入框·标签
inline constexpr int kMd = 6; // 卡片·列表项·浮层·菜单
inline constexpr int kLg = 8; // 对话框·画布浮窗·分组框
inline constexpr int kPill = 999; // 胶囊标签·开关·计数徽标
} // namespace radius
// 应用专业主题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