Popups / 弹窗

PixelUI框架自带的几种 Popup 适合用来显示短消息、进度或输入一个固定位数的整数。

信息弹窗

1
2
3
if (!ui.showPopupInfo("Saved", "Settings", 80, 30, 1500)) {
// 队列已满或 manager 正在 dispatch
}

进度弹窗

重载接受 int32_t&,固定使用 step 1 和百分比格式,编辑语义使用 CommitOnConfirm

1
2
3
4
int32_t progress_ = 0; // 持久的 App 成员

ui.showPopupProgress(progress_, 0, 100, "Updating", 100, 40, 5000,
[this](int32_t value) { progress_ = value; });

百分比、原始值、缩放值或带单位文本都由 NumericFormatter 选择。

需要自定义 step 或实时编辑时,把 range 和 formatter 配置保存成持久成员:

1
2
3
4
5
6
7
8
9
10
11
NumericRange progressRange_{};
PercentageFormat progressFormat_{&progressRange_, "%"};

void showProgress() {
if (!NumericRange::tryCreate(-40, 120, 5, progressRange_)) return;
auto binding = ValueEditorBinding::reference(
progress_, &SettingsApp::progressChanged, this);
ui.showPopupProgress(binding, progressRange_,
NumericFormatter::percentage(progressFormat_),
"Updating", 100, 40, 5000, ValueEditPolicy::Live);
}

进度弹窗的输入会按下述编辑策略处理:

输入 CommitOnConfirm Live
LEFT/RIGHT 只按 range.step() 修改 draft 每次成功步进都立即写回并通知
SELECT 值有变化时写回并通知,然后关闭 关闭,不额外通知
BACK 丢弃 draft 并关闭 值有变化时恢复并通知 original value,然后关闭

Binding 写入失败时,弹窗保持打开,并维持一致的 draft。Session 契约详见通用数值层

固定位数整数输入

1
2
3
4
5
6
7
8
9
10
11
12
int32_t setpoint = 25;

if (!ui.showPopupValueDigits(
setpoint,
3, // 1..PIXELUI_MAX_INT_FIXED_WIDTH
"Target",
100,
56,
3000,
[this](int32_t value) { target_ = value; })) {
// request rejected
}

构造和排队都不会修改 setpoint。位数可以是 1 到 PIXELUI_MAX_INT_FIXED_WIDTH

编辑器分为两层交互。焦点会在所有数字位、OK 和 CANCEL 之间移动。选中数字位会进入该位的局部编辑态;再次按 SELECT 只退出这一位的编辑态,弹窗继续保持打开。

状态与输入 结果
数字位获得焦点 + SELECT 进入该位的局部编辑态
活动数字位 + LEFT/RIGHT 只修改这一位
活动数字位 + SELECT 结束这一位的编辑;不提交,也不关闭
OK + SELECT 汇总所有数字、提交并关闭
CANCEL + SELECT,或任意状态下 BACK 取消整个 Session 并关闭
超时、clearPopups() 或析构 取消尚未完成的 Session

兼容重载使用 CommitOnConfirm:只有在 OK 提交且组合值确实变化时,回调才执行一次;CANCEL 和 BACK 不调用它。使用 ValueEditorBinding 重载并选择 ValueEditPolicy::Live 时,每次成功修改数字都会立即写回并通知;任何取消路径都会在值发生变化时恢复并通知 original value。

默认布局为 100x56。最小高度是 56;最小宽度取数字行与 OK/CANCEL 操作行中较宽者。低于这些限制或大于实际 display 的请求会在入队前被拒绝。默认编辑器无法在 96x40 display 上打开。

返回值 false 表示 Binding、位数、请求布局、display 边界、队列容量或受保护 dispatch 状态拒绝了请求;true 只表示请求已接受,非 owning 数据仍须覆盖 pending 和 active 的完整寿命。

队列和容量

PopupManager 是固定容量 FIFO:

1
active Popup -> pending request 1 -> pending request 2
  • 只有 active Popup 会被构造、绘制和接收输入。
  • pending 项是入队前完成类型校验的 etl::variant<InfoRequest, ProgressRequest, ValueDigitsRequest> 描述符,按先进先出处理。
  • PIXELUI_MAX_POPUP_NUM 包含 active 和 pending。
  • 没有 priority 和抢占;队列满时新请求返回 false
  • active Popup 存在单槽 etl::variant_pool中,完成后销毁,再在同一个稳定槽位构造下一个。
  • 请求回调沿队列移动到 active Popup,不会复制。
  • 销毁 Popup 只停止自己的动画,不会清理无关的 App 动画。

生命周期与重入

text/title/font 指针、Binding context、Formatter context 及其引用的 suffix/range、注入的 Session,以及回调捕获的引用都是非拥有的。排队会把寿命要求延长到 pending 和 active 两个阶段全部结束,而不只是 showPopup...() 返回之后。

App pop 时会清理 active 和 pending Popup。若数据来自寿命更短的 owner,应提前调用 clearPopups()

PopupManager 在构造、销毁、更新、绘制和派发输入期间拒绝 enqueue 和 clear。因此这些回调里不要同步打开或清理 Popup;记下 pending action,等当前 dispatch 返回后再做。保护区之外的普通连续调用,只要容量足够,仍按 FIFO 接受。

avatar
Link0327
喵🐱me0w, but furry wolf. 尝试变得毛茸茸
Link's Github
最新文章
网站信息
文章数目 :
2
本站访客数 :
本站总浏览量 :
最后更新时间 :