feat(desktop): add complete theme switching and suppress mouse selection
This commit is contained in:
parent
b94e19ad7a
commit
af9803f8aa
@ -24,10 +24,12 @@ For native help, pointer, hover-style, or keymap demonstration work, maintain `e
|
||||
|
||||
For layer, overlap, positioning, or anchored-menu demonstrations, maintain `examples/layer-reference.ebox` and its same-basename companion, preserve `examples/layer-minimal.ebox` as the minimal fixture, and run `make layer-tests`. Extend `tests/ebox-playground-layer-tests.el` for actual native commands and committed-snapshot render parity instead of creating another demo runner or probe. Keep layout in the DSL, business state/actions in the companion, and one font size throughout positioned content. Use the shared interaction evaluator above for repeated layer-command timing. Each parent creates its local stacking group automatically; use `:layer root` on a nested absolute node when root projection is required, with semantic `:anchor` and `:placement` declarations for anchored menus.
|
||||
|
||||
For direct-manipulation desktop windows, click-to-front, and title-bar dragging,
|
||||
For direct-manipulation desktop windows, click-to-front, title-bar dragging,
|
||||
complete light/dark palettes, and desktop-only mouse selection policy,
|
||||
maintain `examples/desktop-reference.ebox` with its companion and run
|
||||
`make desktop-tests`. Reuse `tests/ebox-playground-desktop-tests.el` for native
|
||||
press/motion/release streams, intermediate publication and fresh-render parity.
|
||||
press/motion/release streams, gap/end-of-buffer selection fallbacks, palette
|
||||
round trips, intermediate publication and fresh-render parity.
|
||||
Use the shared interaction evaluator with the desktop's `"01 ST"` dock label
|
||||
and `"M-<right>"` for repeated position publication timing. Keep native gesture
|
||||
state in the companion, use public Ebox updates, and preserve the existing layer
|
||||
|
||||
13
DESIGN.md
13
DESIGN.md
@ -94,6 +94,12 @@
|
||||
cyan Signal, amber Notes, mint Terminal and rose Palette accents. One configured
|
||||
font size throughout. Use contrasting title bars and compact pane content,
|
||||
rather than fake close controls, images or additional font packages.
|
||||
- Light theme: a warm pale shell, blue-gray workspace, and five pastel card
|
||||
bodies with dark ink. Retune every caption, active/inactive title, dock entry,
|
||||
waveform, artwork and swatch; changing only the workspace background is not
|
||||
an acceptable light theme. Keep text contrast strong and decorative dots quiet.
|
||||
Palette declarations stay in the DSL; semantic classes connect them to the
|
||||
companion's public selector/region updates, without a global stylesheet.
|
||||
- Structure: compact identity/utility bar, clipped desktop with five independent
|
||||
sibling windows, then persistent dock and status. Keep the workspace dominant;
|
||||
each pane contains a distinct editorial/code/task/signal composition.
|
||||
@ -101,8 +107,15 @@
|
||||
during native mouse tracking, apply the final release position, and retain the
|
||||
last accepted position after interruption. No inertial or decorative animation.
|
||||
The current Ebox layer contract uses pixel X and host-text-row Y coordinates.
|
||||
- Mouse selection: gaps, background rows, line endings and buffer end are desktop
|
||||
surfaces too. A desktop-only minor mode remaps native selection fallbacks;
|
||||
control keymaps keep their click/drag behavior. Remove the policy on unmount
|
||||
or replacement by another example. Do not change global mouse bindings.
|
||||
- Keyboard: RET/SPC activates a pane or dock entry; title-bar Alt+arrows move it.
|
||||
Reset restores the original arrangement. No changes to global Emacs bindings.
|
||||
- LIGHT/DARK toggles the complete palette in one publication and keeps geometry,
|
||||
stacking and active window. Reset keeps the chosen theme; fresh previews start
|
||||
dark and keep independent theme state.
|
||||
- Responsive behavior: use viewport-relative positions and bounded pane widths;
|
||||
overflow is clipped at the desktop boundary. Dock entries remain available for
|
||||
covered panes. Target at least 40 columns and 20 text rows; smaller workspaces
|
||||
|
||||
@ -13,12 +13,21 @@
|
||||
Palette。各窗口有独立内容和局部层叠,全部使用当前字体大小;标题栏与底部窗口栏标出
|
||||
活动窗口,不添加假的关闭按钮或自动动画。
|
||||
|
||||
亮色主题使用暖白外框、浅蓝灰工作区和五种浅色卡片,搭配深色正文。标题栏、窗口入口、
|
||||
辅助文字、波形、嵌套图案与色板都单独适配,不能只把工作台背景换亮。配色表保留在
|
||||
DSL 中,以语义 class 连接 companion 的公开 selector/region 更新,不使用全局样式表。
|
||||
|
||||
点击露出的标题、正文或底部窗口入口时整窗置顶;按住标题栏拖拽时即时发布位置,保留
|
||||
鼠标抓取偏移,并应用松手的最终位置。横向按像素,纵向遵循文本行网格。中断保留最后
|
||||
成功的位置,手势退出不留下 timer、advice 或全局键位。RET/SPC 激活,标题或窗口栏的
|
||||
Alt+方向键移动窗口,RESET 恢复原始位置与次序。业务状态只在 Ebox 发布成功后提交,
|
||||
每个预览独立。
|
||||
|
||||
LIGHT/DARK 在一次发布中切换完整配色,保留位置、层次和活动窗口;RESET 不改变主题。
|
||||
新预览默认深色。Desktop 局部 minor mode 拦截背景、按钮间隙、换行和缓冲区末尾的原生
|
||||
鼠标选区命令,保留按钮与标题栏自身的行为。卸载或切换成其他示例后移除该策略,
|
||||
不修改 Emacs 的全局鼠标绑定。
|
||||
|
||||
结构为紧凑页头与工具栏、裁剪的主工作区、固定窗口栏和坐标状态;推荐至少 40 列、
|
||||
20 行。较小尺寸保留窗口入口,RESET 可找回拖出边界的窗口。测试覆盖真实 keymap
|
||||
命令、中间运动帧、松手、遮挡归属、失败回滚及独立渲染一致性。遵守不操作用户 GUI
|
||||
|
||||
@ -53,6 +53,13 @@ text and layered artwork. All text uses the configured font size.
|
||||
- The five dock entries raise windows even when they are completely covered.
|
||||
**CYCLE** brings the backmost window forward; **RESET** restores all initial
|
||||
positions and the original stack, including panes clipped off the desktop.
|
||||
- **LIGHT/DARK** switches the complete palette: workspace, all five card bodies,
|
||||
text, title bars, dock, artwork, swatches and hover colors. Light mode uses
|
||||
pastel cards with dark ink. Window positions and stacking survive a toggle;
|
||||
**RESET** keeps the chosen theme.
|
||||
- Mouse clicks and drags do not select text, including between dock buttons and
|
||||
at line/buffer ends. This policy belongs only to the Desktop preview; ordinary
|
||||
buffers and other examples keep their normal mouse behavior.
|
||||
- `RET`/`SPC` activates the control at point. `Alt+arrows` on a title or dock
|
||||
entry moves its pane; point follows the same native control for key repeat.
|
||||
`C-g` stops a drag and keeps the last accepted position.
|
||||
|
||||
@ -43,6 +43,13 @@ ECSS 0.1.0 与 TP 1.0.1 是互相独立的包,安装顺序任意;两者都
|
||||
控件,标题或窗口入口上的 Alt+方向键移动对应窗口并支持连续按键;C-g 结束拖拽,
|
||||
保留最后成功发布的位置。每次打开的预览状态互相独立。
|
||||
|
||||
**LIGHT/DARK** 切换整套配色:五张卡片在亮色模式下都使用浅色底与深色文字,标题栏、
|
||||
窗口入口、装饰图案、波形、色板和悬停颜色也同步适配。切换保留窗口位置与层次,
|
||||
**RESET** 保留所选主题。每个新预览默认深色。
|
||||
|
||||
Desktop 中的鼠标点击与拖动不会选中文本,按钮之间、换行和缓冲区末尾也受保护。
|
||||
这项策略只作用于 Desktop 预览,其他缓冲区和示例仍保留正常的鼠标行为。
|
||||
|
||||
横向按像素移动,纵向遵循 Ebox 的文本行网格。推荐至少 40 列、20 行,更大的预览
|
||||
有更多摆放空间。所有文本保持当前字体大小,不使用额外字体或图片依赖。
|
||||
|
||||
|
||||
@ -1,164 +1,246 @@
|
||||
;; Layout and initial geometry live here; native gestures live in the companion.
|
||||
(let* ((studio (desktop-demo-window-create
|
||||
(let* ((styles
|
||||
'((desktop-root (:background-color "#0B1020" :color "#CFD8EA")
|
||||
(:background-color "#F3F0E8" :color "#263347"))
|
||||
(desktop-brand (:color "#BBA9FF") (:color "#674795"))
|
||||
(desktop-heading (:color "#F1F5FF") (:color "#18263B"))
|
||||
(desktop-muted (:color "#8F9FBD") (:color "#53637A"))
|
||||
(desktop-quiet (:color "#657899") (:color "#596A84"))
|
||||
(desktop-control (:background-color "#25324B" :color "#D7E3F8"
|
||||
:hover-style (:background-color "#354662"))
|
||||
(:background-color "#CBD6E4" :color "#253247"
|
||||
:hover-style (:background-color "#B9C9DE")))
|
||||
(desktop-chrome (:background-color "#25324B" :color "#C1CBE0")
|
||||
(:background-color "#D5DDE8" :color "#344359"))
|
||||
(desktop-workspace (:background-color "#111A2C")
|
||||
(:background-color "#E3E8EF"))
|
||||
(desktop-grid-label (:color "#3F5273") (:color "#566B86"))
|
||||
(desktop-grid-dots (:color "#334866") (:color "#A6B3C3"))
|
||||
(desktop-grid-hint (:color "#5A6D8E") (:color "#566A83"))
|
||||
(desktop-studio (:background-color "#26223B" :color "#D6CDEF")
|
||||
(:background-color "#E9E3F2" :color "#4F3F67"))
|
||||
(desktop-studio-heading (:color "#F5F0FF") (:color "#37284F"))
|
||||
(desktop-studio-caption (:color "#A999C8") (:color "#67577E"))
|
||||
(desktop-studio-text (:color "#B8A9D0") (:color "#5F4D78"))
|
||||
(desktop-studio-muted (:color "#85799F") (:color "#6D587F"))
|
||||
(desktop-art-form (:background-color "#7561AC" :color "#EAE1FF")
|
||||
(:background-color "#C9BCE3" :color "#453259"))
|
||||
(desktop-art-space (:background-color "#BBA9FF" :color "#302449")
|
||||
(:background-color "#DED3F6" :color "#51356C"))
|
||||
(desktop-art-play (:background-color "#D8EAAB" :color "#303D22")
|
||||
(:background-color "#DBE8C3" :color "#41512B"))
|
||||
(desktop-notes (:background-color "#EEE3CB" :color "#514430")
|
||||
(:background-color "#FFF4D8" :color "#5B482B"))
|
||||
(desktop-notes-caption (:color "#8C744E") (:color "#7A623E"))
|
||||
(desktop-notes-muted (:color "#887651") (:color "#836D49"))
|
||||
(desktop-notes-rule (:color "#A18B61") (:color "#A38E65"))
|
||||
(desktop-notes-footer (:color "#746345") (:color "#705935"))
|
||||
(desktop-signal (:background-color "#17343E" :color "#BFE5E9")
|
||||
(:background-color "#DBEEF0" :color "#315B65"))
|
||||
(desktop-signal-heading (:color "#E4FBF9") (:color "#184B57"))
|
||||
(desktop-signal-caption (:color "#7BAEB9") (:color "#436971"))
|
||||
(desktop-signal-muted (:color "#699CA9") (:color "#496F77"))
|
||||
(desktop-signal-accent (:color "#8DE1E4") (:color "#2E7280"))
|
||||
(desktop-wave-muted (:background-color "#518F9D") (:background-color "#9EC9CF"))
|
||||
(desktop-wave-cyan (:background-color "#8DE1E4") (:background-color "#5EADB5"))
|
||||
(desktop-wave-violet (:background-color "#BBA9FF") (:background-color "#927AC9"))
|
||||
(desktop-terminal (:background-color "#101F22" :color "#B6D7CC")
|
||||
(:background-color "#E0EEE4" :color "#355E4C"))
|
||||
(desktop-terminal-accent (:color "#A7E8BB") (:color "#256544"))
|
||||
(desktop-terminal-muted (:color "#608C7F") (:color "#496D5B"))
|
||||
(desktop-palette (:background-color "#39283D" :color "#EBCBDE")
|
||||
(:background-color "#F0E1EB" :color "#65485E"))
|
||||
(desktop-palette-caption (:color "#AF8DA9") (:color "#7B5670"))
|
||||
(desktop-palette-accent (:color "#F3A8C9") (:color "#925277"))
|
||||
(desktop-swatch-violet (:background-color "#BBA9FF") (:background-color "#9578CF"))
|
||||
(desktop-swatch-amber (:background-color "#F6C879") (:background-color "#DEB251"))
|
||||
(desktop-swatch-cyan (:background-color "#8DE1E4") (:background-color "#58A7AF"))
|
||||
(desktop-swatch-mint (:background-color "#A7E8BB") (:background-color "#72AB83"))
|
||||
(desktop-swatch-rose (:background-color "#F3A8C9") (:background-color "#CE87AA"))))
|
||||
(studio (desktop-demo-window-create
|
||||
:id "desk-studio" :label "STUDIO" :accent "#BBA9FF" :ink "#241B40"
|
||||
:light-accent "#6D4AA2" :light-ink "#FFFFFF"
|
||||
:left '(% 5) :top '(lh 1)))
|
||||
(notes (desktop-demo-window-create
|
||||
:id "desk-notes" :label "NOTES" :accent "#F6C879" :ink "#3B2917"
|
||||
:light-accent "#8C6421" :light-ink "#FFFFFF"
|
||||
:left '(% 45) :top '(% 4)))
|
||||
(signal (desktop-demo-window-create
|
||||
:id "desk-signal" :label "SIGNAL" :accent "#8DE1E4" :ink "#15383D"
|
||||
:light-accent "#246675" :light-ink "#FFFFFF"
|
||||
:left '(% 57) :top '(% 32)))
|
||||
(terminal (desktop-demo-window-create
|
||||
:id "desk-terminal" :label "TERMINAL" :accent "#A7E8BB" :ink "#1B3826"
|
||||
:light-accent "#2F674B" :light-ink "#FFFFFF"
|
||||
:left '(% 8) :top '(% 46)))
|
||||
(palette (desktop-demo-window-create
|
||||
:id "desk-palette" :label "PALETTE" :accent "#F3A8C9" :ink "#402438"
|
||||
:light-accent "#875270" :light-ink "#FFFFFF"
|
||||
:left '(% 43) :top '(% 65)))
|
||||
(panes (list studio notes signal terminal palette))
|
||||
(demo (desktop-demo-create :windows panes
|
||||
(demo (desktop-demo-create :windows panes :styles styles
|
||||
:order (mapcar #'desktop-demo-window-id panes)
|
||||
:active "desk-palette")))
|
||||
`(column :width (vw 100) :height (vh 100) :overflow hidden
|
||||
:background-color "#0B1020" :color "#CFD8EA"
|
||||
`(column :id "desktop-root" :class desktop-root
|
||||
:width (vw 100) :height (vh 100) :overflow hidden
|
||||
,@(desktop-demo-style demo 'desktop-root)
|
||||
(box :height (lh 3) :padding-inline (ch 1)
|
||||
(row :height (lh 1)
|
||||
(box :color "#BBA9FF" :font-weight bold "P A R A L L A X")
|
||||
(box :padding-left (ch 2) :color "#657899" "DESKTOP / 05"))
|
||||
(box :color "#F1F5FF" "A little space. A lot of possibilities.")
|
||||
(box :color "#8F9FBD" "Click to focus. Drag a title bar to move."))
|
||||
(box :class desktop-brand ,@(desktop-demo-style demo 'desktop-brand)
|
||||
:font-weight bold "P A R A L L A X")
|
||||
(box :padding-left (ch 2) :class desktop-quiet
|
||||
,@(desktop-demo-style demo 'desktop-quiet) "DESKTOP / 05"))
|
||||
(box :class desktop-heading ,@(desktop-demo-style demo 'desktop-heading)
|
||||
"A little space. A lot of possibilities.")
|
||||
(box :class desktop-muted ,@(desktop-demo-style demo 'desktop-muted)
|
||||
"Click to focus. Drag a title bar to move."))
|
||||
(flex :height (lh 1) :gap ((lh 0) (ch 1)) :padding-inline (ch 1)
|
||||
(box :padding-inline (ch 1) :color "#D7E3F8" :background-color "#25324B"
|
||||
:pointer hand :hover-style (:background-color "#354662")
|
||||
(box :padding-inline (ch 1) :flex-shrink 0 :class desktop-control
|
||||
,@(desktop-demo-style demo 'desktop-control) :pointer hand
|
||||
:help-echo "Restore the five original positions and stacking order."
|
||||
:keymap ,(desktop-demo-control demo 'reset) "RESET")
|
||||
(box :padding-inline (ch 1) :color "#D7E3F8" :background-color "#25324B"
|
||||
:pointer hand :hover-style (:background-color "#354662")
|
||||
(box :padding-inline (ch 1) :flex-shrink 0 :class desktop-control
|
||||
,@(desktop-demo-style demo 'desktop-control) :pointer hand
|
||||
:help-echo "Bring the backmost window to the front."
|
||||
:keymap ,(desktop-demo-control demo 'next) "CYCLE")
|
||||
(box :color "#657899" "FIVE IDEAS / ONE SHARED SPACE"))
|
||||
(box :id "desktop-theme" :class desktop-control
|
||||
,@(desktop-demo-style demo 'desktop-control)
|
||||
:width (ch 7) :flex-shrink 0 :text-align center :pointer hand
|
||||
:help-echo "Switch the whole desktop between light and dark palettes."
|
||||
:keymap ,(desktop-demo-control demo 'theme) "LIGHT")
|
||||
(box :class desktop-quiet :min-width (px 0) :overflow hidden :wrap-mode none
|
||||
,@(desktop-demo-style demo 'desktop-quiet)
|
||||
"FIVE IDEAS / ONE SHARED SPACE"))
|
||||
|
||||
(box :id "desktop-canvas" :height (calc (- (vh 100) (lh 7)))
|
||||
:overflow hidden :background-color "#111A2C"
|
||||
:overflow hidden :class desktop-workspace
|
||||
,@(desktop-demo-style demo 'desktop-workspace)
|
||||
(box :position absolute :left (ch 1) :top (lh 0)
|
||||
:color "#3F5273" "WORKSPACE 01 + + + + +")
|
||||
:class desktop-grid-label ,@(desktop-demo-style demo 'desktop-grid-label)
|
||||
"WORKSPACE 01 + + + + +")
|
||||
(box :position absolute :left (% 68) :top (% 78)
|
||||
:width (% 30) :color "#334866"
|
||||
:width (% 30) :class desktop-grid-dots ,@(desktop-demo-style demo 'desktop-grid-dots)
|
||||
"+ . + . +\n. + . + .\n+ . + . +\n. + . + .")
|
||||
(box :position absolute :left (ch 2) :top (% 93)
|
||||
:color "#5A6D8E" "MOVE THINGS AROUND. MAKE IT YOURS.")
|
||||
:class desktop-grid-hint ,@(desktop-demo-style demo 'desktop-grid-hint)
|
||||
"MOVE THINGS AROUND. MAKE IT YOURS.")
|
||||
|
||||
(box :id "desk-studio" :position absolute :left ,(desktop-demo-window-left studio)
|
||||
:top ,(desktop-demo-window-top studio) :width (min (ch 44) (% 55))
|
||||
:height (lh 13) :z-index 1 :overflow hidden
|
||||
:background-color "#26223B" :color "#D6CDEF" :pointer arrow
|
||||
:class desktop-studio ,@(desktop-demo-style demo 'desktop-studio) :pointer arrow
|
||||
:help-echo "Studio. Click any exposed area to bring this whole window forward."
|
||||
:keymap ,(desktop-demo-keymap demo "desk-studio")
|
||||
(box :id "desk-studio-title" :height (lh 1) :padding-inline (ch 1)
|
||||
:background-color "#25324B" :color "#C1CBE0" :font-weight bold
|
||||
:class desktop-chrome ,@(desktop-demo-style demo 'desktop-chrome) :font-weight bold
|
||||
:pointer hand :keymap ,(desktop-demo-keymap demo "desk-studio" t)
|
||||
:help-echo "Drag Studio. Alt+arrows moves it from the keyboard."
|
||||
"STUDIO / 01 ::")
|
||||
(box :padding ((lh 1) (ch 2))
|
||||
(box :font-weight bold :color "#F5F0FF" "Make space for the unexpected.")
|
||||
(box :padding-top (lh 1) :color "#A999C8" "EXPERIMENT 024 / SOFT STRUCTURES")
|
||||
(box :font-weight bold :class desktop-studio-heading ,@(desktop-demo-style demo 'desktop-studio-heading) "Make space for the unexpected.")
|
||||
(box :padding-top (lh 1) :class desktop-studio-caption ,@(desktop-demo-style demo 'desktop-studio-caption) "EXPERIMENT 024 / SOFT STRUCTURES")
|
||||
(box :height (lh 5) :padding-top (lh 1)
|
||||
(box :position absolute :left (ch 0) :top (lh 1)
|
||||
:width (ch 13) :height (lh 3) :background-color "#7561AC"
|
||||
:color "#EAE1FF" :text-align center "\nFORM / 01")
|
||||
:width (ch 13) :height (lh 3) :class desktop-art-form ,@(desktop-demo-style demo 'desktop-art-form) :text-align center "\nFORM / 01")
|
||||
(box :position absolute :left (ch 9) :top (lh 0)
|
||||
:width (ch 13) :height (lh 3) :z-index 1
|
||||
:background-color "#BBA9FF" :color "#302449"
|
||||
:class desktop-art-space ,@(desktop-demo-style demo 'desktop-art-space)
|
||||
:text-align center "\nSPACE / 02")
|
||||
(box :position absolute :left (ch 18) :top (lh 2)
|
||||
:width (ch 12) :height (lh 3) :z-index 2
|
||||
:background-color "#D8EAAB" :color "#303D22"
|
||||
:class desktop-art-play ,@(desktop-demo-style demo 'desktop-art-play)
|
||||
:text-align center "\nPLAY / 03"))
|
||||
(box :color "#B8A9D0" "Fragments become a composition.")
|
||||
(box :padding-top (lh 1) :color "#85799F" "COLLECTION / UNFINISHED POSSIBILITIES")))
|
||||
(box :class desktop-studio-text ,@(desktop-demo-style demo 'desktop-studio-text) "Fragments become a composition.")
|
||||
(box :padding-top (lh 1) :class desktop-studio-muted ,@(desktop-demo-style demo 'desktop-studio-muted) "COLLECTION / UNFINISHED POSSIBILITIES")))
|
||||
|
||||
(box :id "desk-notes" :position absolute :left ,(desktop-demo-window-left notes)
|
||||
:top ,(desktop-demo-window-top notes) :width (min (ch 34) (% 43))
|
||||
:height (lh 11) :z-index 2 :overflow hidden
|
||||
:background-color "#EEE3CB" :color "#514430" :pointer arrow
|
||||
:class desktop-notes ,@(desktop-demo-style demo 'desktop-notes) :pointer arrow
|
||||
:help-echo "Notes. The content remains here even when another window covers it."
|
||||
:keymap ,(desktop-demo-keymap demo "desk-notes")
|
||||
(box :id "desk-notes-title" :height (lh 1) :padding-inline (ch 1)
|
||||
:background-color "#25324B" :color "#C1CBE0" :font-weight bold
|
||||
:class desktop-chrome ,@(desktop-demo-style demo 'desktop-chrome) :font-weight bold
|
||||
:pointer hand :keymap ,(desktop-demo-keymap demo "desk-notes" t)
|
||||
:help-echo "Drag Notes. Alt+arrows moves it from the keyboard."
|
||||
"NOTES / 02 ::")
|
||||
(box :padding ((lh 1) (ch 1))
|
||||
(box :font-weight bold "A quieter kind of focus.")
|
||||
(box :padding-top (lh 1) :color "#8C744E" "TODAY / THINGS WORTH MAKING")
|
||||
(box :padding-top (lh 1) :class desktop-notes-caption ,@(desktop-demo-style demo 'desktop-notes-caption) "TODAY / THINGS WORTH MAKING")
|
||||
(box :padding-top (lh 1)
|
||||
"[x] Collect the small ideas\n[ ] Give the good ones room\n[ ] Leave something unfinished")
|
||||
(box :padding-top (lh 1) :color "#887651" "Less noise. More intention.")
|
||||
(box :color "#A18B61" "------------------------------")
|
||||
(box :color "#746345" "03 NOTES / SAVED IN THE MOMENT")))
|
||||
(box :padding-top (lh 1) :class desktop-notes-muted ,@(desktop-demo-style demo 'desktop-notes-muted) "Less noise. More intention.")
|
||||
(box :class desktop-notes-rule ,@(desktop-demo-style demo 'desktop-notes-rule) "------------------------------")
|
||||
(box :class desktop-notes-footer ,@(desktop-demo-style demo 'desktop-notes-footer) "03 NOTES / SAVED IN THE MOMENT")))
|
||||
|
||||
(box :id "desk-signal" :position absolute :left ,(desktop-demo-window-left signal)
|
||||
:top ,(desktop-demo-window-top signal) :width (min (ch 32) (% 39))
|
||||
:height (lh 10) :z-index 3 :overflow hidden
|
||||
:background-color "#17343E" :color "#BFE5E9" :pointer arrow
|
||||
:class desktop-signal ,@(desktop-demo-style demo 'desktop-signal) :pointer arrow
|
||||
:help-echo "Signal. Raise the entire player, including its overlapping waveform."
|
||||
:keymap ,(desktop-demo-keymap demo "desk-signal")
|
||||
(box :id "desk-signal-title" :height (lh 1) :padding-inline (ch 1)
|
||||
:background-color "#25324B" :color "#C1CBE0" :font-weight bold
|
||||
:class desktop-chrome ,@(desktop-demo-style demo 'desktop-chrome) :font-weight bold
|
||||
:pointer hand :keymap ,(desktop-demo-keymap demo "desk-signal" t)
|
||||
:help-echo "Drag Signal. Alt+arrows moves it from the keyboard."
|
||||
"SIGNAL / 03 ::")
|
||||
(box :padding ((lh 1) (ch 2))
|
||||
(box :font-weight bold :color "#E4FBF9" "AFTER HOURS")
|
||||
(box :color "#7BAEB9" "A soundtrack for the in-between.")
|
||||
(box :font-weight bold :class desktop-signal-heading ,@(desktop-demo-style demo 'desktop-signal-heading) "AFTER HOURS")
|
||||
(box :class desktop-signal-caption ,@(desktop-demo-style demo 'desktop-signal-caption) "A soundtrack for the in-between.")
|
||||
(flex :height (lh 3) :gap ((lh 0) (ch 1)) :padding-top (lh 1)
|
||||
(box :width (ch 2) :height (lh 1) :background-color "#518F9D")
|
||||
(box :width (ch 2) :height (lh 2) :background-color "#8DE1E4")
|
||||
(box :width (ch 2) :height (lh 1) :background-color "#518F9D")
|
||||
(box :width (ch 2) :height (lh 2) :background-color "#BBA9FF")
|
||||
(box :width (ch 2) :height (lh 1) :background-color "#8DE1E4")
|
||||
(box :width (ch 2) :height (lh 2) :background-color "#BBA9FF")
|
||||
(box :width (ch 2) :height (lh 1) :background-color "#518F9D"))
|
||||
(box :color "#8DE1E4" "========------------ 03:42")
|
||||
(box :padding-top (lh 1) :color "#699CA9" "SIDE B / SLOWER ORBITS")))
|
||||
(box :width (ch 2) :height (lh 1) :class desktop-wave-muted ,@(desktop-demo-style demo 'desktop-wave-muted))
|
||||
(box :width (ch 2) :height (lh 2) :class desktop-wave-cyan ,@(desktop-demo-style demo 'desktop-wave-cyan))
|
||||
(box :width (ch 2) :height (lh 1) :class desktop-wave-muted ,@(desktop-demo-style demo 'desktop-wave-muted))
|
||||
(box :width (ch 2) :height (lh 2) :class desktop-wave-violet ,@(desktop-demo-style demo 'desktop-wave-violet))
|
||||
(box :width (ch 2) :height (lh 1) :class desktop-wave-cyan ,@(desktop-demo-style demo 'desktop-wave-cyan))
|
||||
(box :width (ch 2) :height (lh 2) :class desktop-wave-violet ,@(desktop-demo-style demo 'desktop-wave-violet))
|
||||
(box :width (ch 2) :height (lh 1) :class desktop-wave-muted ,@(desktop-demo-style demo 'desktop-wave-muted)))
|
||||
(box :class desktop-signal-accent ,@(desktop-demo-style demo 'desktop-signal-accent) "========------------ 03:42")
|
||||
(box :padding-top (lh 1) :class desktop-signal-muted ,@(desktop-demo-style demo 'desktop-signal-muted) "SIDE B / SLOWER ORBITS")))
|
||||
|
||||
(box :id "desk-terminal" :position absolute :left ,(desktop-demo-window-left terminal)
|
||||
:top ,(desktop-demo-window-top terminal) :width (min (ch 48) (% 60))
|
||||
:height (lh 11) :z-index 4 :overflow hidden
|
||||
:background-color "#101F22" :color "#B6D7CC" :pointer arrow
|
||||
:class desktop-terminal ,@(desktop-demo-style demo 'desktop-terminal) :pointer arrow
|
||||
:help-echo "Terminal. This sample transcript is part of the movable text window."
|
||||
:keymap ,(desktop-demo-keymap demo "desk-terminal")
|
||||
(box :id "desk-terminal-title" :height (lh 1) :padding-inline (ch 1)
|
||||
:background-color "#25324B" :color "#C1CBE0" :font-weight bold
|
||||
:class desktop-chrome ,@(desktop-demo-style demo 'desktop-chrome) :font-weight bold
|
||||
:pointer hand :keymap ,(desktop-demo-keymap demo "desk-terminal" t)
|
||||
:help-echo "Drag Terminal. Alt+arrows moves it from the keyboard."
|
||||
"TERMINAL / 04 ::")
|
||||
(box :padding ((lh 1) (ch 2))
|
||||
(box :color "#A7E8BB" "$ build something good")
|
||||
(box :padding-top (lh 1) :color "#608C7F" " session: creative / local\n workspace: parallax")
|
||||
(box :class desktop-terminal-accent ,@(desktop-demo-style demo 'desktop-terminal-accent) "$ build something good")
|
||||
(box :padding-top (lh 1) :class desktop-terminal-muted ,@(desktop-demo-style demo 'desktop-terminal-muted) " session: creative / local\n workspace: parallax")
|
||||
(box :padding-top (lh 1) " + ideas connected\n + room for experiments\n + all five windows ready")
|
||||
(box :padding-top (lh 1) :color "#A7E8BB" " READY / follow your curiosity")))
|
||||
(box :padding-top (lh 1) :class desktop-terminal-accent ,@(desktop-demo-style demo 'desktop-terminal-accent) " READY / follow your curiosity")))
|
||||
|
||||
(box :id "desk-palette" :position absolute :left ,(desktop-demo-window-left palette)
|
||||
:top ,(desktop-demo-window-top palette) :width (min (ch 29) (% 36))
|
||||
:height (lh 9) :z-index 5 :overflow hidden
|
||||
:background-color "#39283D" :color "#EBCBDE" :pointer arrow
|
||||
:class desktop-palette ,@(desktop-demo-style demo 'desktop-palette) :pointer arrow
|
||||
:help-echo "Palette starts in front. Click a window underneath to change the stack."
|
||||
:keymap ,(desktop-demo-keymap demo "desk-palette")
|
||||
(box :id "desk-palette-title" :height (lh 1) :padding-inline (ch 1)
|
||||
:background-color "#F3A8C9" :color "#402438" :font-weight bold
|
||||
:class desktop-chrome ,@(desktop-demo-chrome-style demo palette t) :font-weight bold
|
||||
:pointer hand :keymap ,(desktop-demo-keymap demo "desk-palette" t)
|
||||
:help-echo "Drag Palette. Alt+arrows moves it from the keyboard."
|
||||
"PALETTE / 05 ::")
|
||||
(box :padding ((lh 1) (ch 1))
|
||||
(box :font-weight bold "Objects in conversation.")
|
||||
(box :padding-top (lh 1) :color "#AF8DA9" "FIVE TONES / ONE ATMOSPHERE")
|
||||
(box :padding-top (lh 1) :class desktop-palette-caption ,@(desktop-demo-style demo 'desktop-palette-caption) "FIVE TONES / ONE ATMOSPHERE")
|
||||
(flex :height (lh 2) :padding-top (lh 1) :gap ((lh 0) (ch 1))
|
||||
(box :width (ch 4) :height (lh 1) :background-color "#BBA9FF")
|
||||
(box :width (ch 4) :height (lh 1) :background-color "#F6C879")
|
||||
(box :width (ch 4) :height (lh 1) :background-color "#8DE1E4")
|
||||
(box :width (ch 4) :height (lh 1) :background-color "#A7E8BB")
|
||||
(box :width (ch 4) :height (lh 1) :background-color "#F3A8C9"))
|
||||
(box :padding-top (lh 1) :color "#F3A8C9" "MIDNIGHT / SOFT ELECTRIC"))))
|
||||
(box :width (ch 4) :height (lh 1) :class desktop-swatch-violet
|
||||
,@(desktop-demo-style demo 'desktop-swatch-violet))
|
||||
(box :width (ch 4) :height (lh 1) :class desktop-swatch-amber
|
||||
,@(desktop-demo-style demo 'desktop-swatch-amber))
|
||||
(box :width (ch 4) :height (lh 1) :class desktop-swatch-cyan
|
||||
,@(desktop-demo-style demo 'desktop-swatch-cyan))
|
||||
(box :width (ch 4) :height (lh 1) :class desktop-swatch-mint
|
||||
,@(desktop-demo-style demo 'desktop-swatch-mint))
|
||||
(box :width (ch 4) :height (lh 1) :class desktop-swatch-rose
|
||||
,@(desktop-demo-style demo 'desktop-swatch-rose)))
|
||||
(box :padding-top (lh 1) :class desktop-palette-accent ,@(desktop-demo-style demo 'desktop-palette-accent) "MIDNIGHT / SOFT ELECTRIC"))))
|
||||
|
||||
(flex :height (lh 2) :gap ((lh 0) (ch 1)) :padding-top (lh 1)
|
||||
,@(cl-loop for pane in panes for index from 1
|
||||
@ -167,12 +249,11 @@
|
||||
collect
|
||||
`(box :id ,(concat (desktop-demo-window-id pane) "-dock")
|
||||
:padding-inline (ch 1)
|
||||
:background-color ,(if active (desktop-demo-window-accent pane) "#25324B")
|
||||
:color ,(if active (desktop-demo-window-ink pane) "#C1CBE0")
|
||||
:class desktop-chrome ,@(desktop-demo-chrome-style demo pane active)
|
||||
:font-weight bold :pointer hand
|
||||
:help-echo ,(format "Bring %s to front, even when covered. Alt+arrows moves it."
|
||||
(desktop-demo-window-label pane))
|
||||
:keymap ,(desktop-demo-keymap demo (desktop-demo-window-id pane))
|
||||
,(format "%02d %s" index short))))
|
||||
(box :id "desktop-status" :height (lh 1) :color "#8F9FBD"
|
||||
(box :id "desktop-status" :height (lh 1) :class desktop-muted ,@(desktop-demo-style demo 'desktop-muted)
|
||||
,(desktop-demo-status demo))))
|
||||
|
||||
@ -9,14 +9,72 @@
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'ebox)
|
||||
(require 'ebox-selector)
|
||||
|
||||
(defun desktop-demo--dismiss-mouse-selection ()
|
||||
"Consume a native text-selection command in a desktop preview."
|
||||
(interactive)
|
||||
(deactivate-mark))
|
||||
|
||||
(defvar desktop-demo-input-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(dolist (command '(mouse-drag-region mouse-set-region mouse-set-point
|
||||
mouse-save-then-kill mouse-drag-secondary
|
||||
mouse-start-secondary mouse-set-secondary
|
||||
mouse-secondary-save-then-kill))
|
||||
(define-key map (vector 'remap command) #'desktop-demo--dismiss-mouse-selection))
|
||||
map)
|
||||
"Desktop-local fallbacks for mouse events outside individual controls.")
|
||||
|
||||
(defun desktop-demo--clear-mouse-mark ()
|
||||
"Clear a preceding text selection when a desktop mouse command starts."
|
||||
(when (mouse-event-p last-input-event)
|
||||
(deactivate-mark)))
|
||||
|
||||
(define-minor-mode desktop-demo-input-mode
|
||||
"Keep desktop gestures from entering native text selection.
|
||||
Control text keymaps retain their own activation and title-drag commands."
|
||||
:lighter nil :keymap desktop-demo-input-mode-map
|
||||
(if desktop-demo-input-mode
|
||||
(progn
|
||||
(deactivate-mark)
|
||||
(add-hook 'pre-command-hook #'desktop-demo--clear-mouse-mark nil t))
|
||||
(remove-hook 'pre-command-hook #'desktop-demo--clear-mouse-mark t)))
|
||||
|
||||
(defun desktop-demo--sync-input-mode ()
|
||||
"Apply the desktop mouse policy only to a successfully mounted desktop."
|
||||
(desktop-demo-input-mode
|
||||
(if (and ebox-buffer-mode
|
||||
(condition-case nil
|
||||
(ebox-region-resolve (current-buffer) "desktop-root")
|
||||
(user-error nil)))
|
||||
1 -1)))
|
||||
|
||||
(add-hook 'ebox-buffer-mode-hook #'desktop-demo--sync-input-mode)
|
||||
|
||||
(cl-defstruct (desktop-demo-window (:constructor desktop-demo-window-create))
|
||||
"A desktop pane's identity, palette, initial offsets and pixel displacement."
|
||||
id label accent ink left top (x 0) (y 0))
|
||||
id label accent ink light-accent light-ink left top (x 0) (y 0))
|
||||
|
||||
(cl-defstruct (desktop-demo (:constructor desktop-demo-create))
|
||||
"Independent state captured by the native commands of one desktop preview."
|
||||
windows order active (serial 5) dragging)
|
||||
windows order active styles (theme 'dark) (serial 5) dragging)
|
||||
|
||||
(defun desktop-demo-style (demo role)
|
||||
"Return DEMO's current theme declarations for the semantic style ROLE."
|
||||
(let ((entry (assq role (desktop-demo-styles demo))))
|
||||
(unless entry (error "Unknown desktop style: %s" role))
|
||||
(nth (if (eq (desktop-demo-theme demo) 'light) 2 1) entry)))
|
||||
|
||||
(defun desktop-demo-chrome-style (demo pane active)
|
||||
"Return DEMO's themed title/dock declarations for PANE and ACTIVE state."
|
||||
(if active
|
||||
(if (eq (desktop-demo-theme demo) 'light)
|
||||
(list :background-color (desktop-demo-window-light-accent pane)
|
||||
:color (desktop-demo-window-light-ink pane))
|
||||
(list :background-color (desktop-demo-window-accent pane)
|
||||
:color (desktop-demo-window-ink pane)))
|
||||
(desktop-demo-style demo 'desktop-chrome)))
|
||||
|
||||
(defun desktop-demo--window (demo id)
|
||||
"Return DEMO's pane with semantic ID."
|
||||
@ -31,13 +89,11 @@
|
||||
(desktop-demo-window-label pane)
|
||||
(desktop-demo-window-x pane) (desktop-demo-window-y pane))))
|
||||
|
||||
(defun desktop-demo--chrome (pane active)
|
||||
"Return title and dock updates for PANE, highlighted when ACTIVE."
|
||||
(let ((background (if active (desktop-demo-window-accent pane) "#25324B"))
|
||||
(foreground (if active (desktop-demo-window-ink pane) "#C1CBE0")))
|
||||
(defun desktop-demo--chrome (demo pane active)
|
||||
"Return DEMO's themed title and dock updates for PANE and ACTIVE state."
|
||||
(let ((style (desktop-demo-chrome-style demo pane active)))
|
||||
(mapcar (lambda (suffix)
|
||||
(list (concat (desktop-demo-window-id pane) suffix)
|
||||
:background-color background :color foreground))
|
||||
(cons (concat (desktop-demo-window-id pane) suffix) style))
|
||||
'("-title" "-dock"))))
|
||||
|
||||
(defun desktop-demo--keyboard-anchor ()
|
||||
@ -75,6 +131,7 @@ Failed Ebox publication leaves the business state on its accepted generation."
|
||||
(setf (desktop-demo-windows demo) (desktop-demo-windows candidate)
|
||||
(desktop-demo-order demo) (desktop-demo-order candidate)
|
||||
(desktop-demo-active demo) (desktop-demo-active candidate)
|
||||
(desktop-demo-theme demo) (desktop-demo-theme candidate)
|
||||
(desktop-demo-serial demo) (desktop-demo-serial candidate)
|
||||
(desktop-demo-dragging demo) (desktop-demo-dragging candidate))
|
||||
(desktop-demo--restore-keyboard-anchor anchor)))
|
||||
@ -92,8 +149,8 @@ Failed Ebox publication leaves the business state on its accepted generation."
|
||||
demo candidate
|
||||
(append (list (list id :z-index (desktop-demo-serial candidate)))
|
||||
(desktop-demo--chrome
|
||||
(desktop-demo--window demo (desktop-demo-active demo)) nil)
|
||||
(desktop-demo--chrome pane t)))))
|
||||
demo (desktop-demo--window demo (desktop-demo-active demo)) nil)
|
||||
(desktop-demo--chrome demo pane t)))))
|
||||
(when dragging (setf (desktop-demo-dragging demo) id))))
|
||||
|
||||
(defun desktop-demo-move (demo id x y &optional row-height)
|
||||
@ -223,11 +280,29 @@ or failure releases gesture state and keeps the last accepted geometry."
|
||||
:top (desktop-demo-window-top pane) :z-index depth) updates)
|
||||
(setq updates
|
||||
(append updates (desktop-demo--chrome
|
||||
pane (equal active (desktop-demo-window-id pane))))))
|
||||
demo pane (equal active (desktop-demo-window-id pane))))))
|
||||
(setf (desktop-demo-windows candidate) panes (desktop-demo-order candidate) ids
|
||||
(desktop-demo-active candidate) active (desktop-demo-serial candidate) (length ids))
|
||||
(desktop-demo--publish demo candidate updates)))
|
||||
|
||||
(defun desktop-demo-toggle-theme (demo)
|
||||
"Switch DEMO's complete palette without changing window geometry or order."
|
||||
(let ((candidate (copy-desktop-demo demo)) updates)
|
||||
(setf (desktop-demo-theme candidate)
|
||||
(if (eq (desktop-demo-theme demo) 'dark) 'light 'dark))
|
||||
(dolist (entry (desktop-demo-styles demo))
|
||||
(dolist (match (ebox-selector-query-buffer
|
||||
(current-buffer) (concat "." (symbol-name (car entry)))))
|
||||
(when-let* ((handle (plist-get match :region-handle)))
|
||||
(push (cons handle (desktop-demo-style candidate (car entry))) updates))))
|
||||
(desktop-demo--publish
|
||||
demo candidate
|
||||
(append (nreverse updates)
|
||||
(desktop-demo--chrome
|
||||
candidate (desktop-demo--window demo (desktop-demo-active demo)) t)
|
||||
(list (list "desktop-theme" :content
|
||||
(if (eq (desktop-demo-theme candidate) 'light) "DARK" "LIGHT")))))))
|
||||
|
||||
(defun desktop-demo-control (demo action)
|
||||
"Create a native toolbar command for DEMO's ACTION."
|
||||
(ebox-keymap-create
|
||||
@ -236,6 +311,7 @@ or failure releases gesture state and keeps the last accepted geometry."
|
||||
(pcase action
|
||||
('reset (desktop-demo-reset demo))
|
||||
('next (desktop-demo-activate demo (car (desktop-demo-order demo))))
|
||||
('theme (desktop-demo-toggle-theme demo))
|
||||
(_ (error "Unknown desktop action: %s" action))))))
|
||||
|
||||
(provide 'desktop-demo-reference)
|
||||
|
||||
@ -65,6 +65,7 @@
|
||||
(list (copy-sequence (desktop-demo-order demo))
|
||||
(desktop-demo-active demo) (desktop-demo-serial demo)
|
||||
(desktop-demo-dragging demo)
|
||||
(desktop-demo-theme demo)
|
||||
(mapcar (lambda (window)
|
||||
(list (desktop-demo-window-id window)
|
||||
(desktop-demo-window-x window)
|
||||
@ -134,6 +135,175 @@ TYPE defaults to `down-mouse-1'; repeated presses use their native event type."
|
||||
(should (equal (desktop-demo-active ebox-playground-desktop-test--demo)
|
||||
(cdr entry))))))
|
||||
|
||||
(ert-deftest ebox-playground-desktop-gaps-and-endpoints-do-not-select-text ()
|
||||
"Desktop gaps, newlines and buffer end consume native selection commands."
|
||||
(ebox-playground-desktop-test--with-preview (buffer)
|
||||
(should desktop-demo-input-mode)
|
||||
(let* ((dock (ebox-playground-layer-test--position "01 ST"))
|
||||
(gap (next-single-property-change dock 'keymap nil (point-max)))
|
||||
(newline (save-excursion (goto-char dock) (line-end-position)))
|
||||
(transient-mark-mode t))
|
||||
(save-window-excursion
|
||||
(set-window-buffer (selected-window) buffer)
|
||||
(dolist (position (list (point-min) gap newline (point-max)))
|
||||
(dolist (type '(down-mouse-1 mouse-1 drag-mouse-1 S-mouse-1
|
||||
M-down-mouse-1 M-mouse-1 M-drag-mouse-1))
|
||||
(goto-char position)
|
||||
(set-mark (if (= position (point-min)) (point-max) (point-min)))
|
||||
(setq mark-active t)
|
||||
(let* ((event (ebox-playground-desktop-test--event
|
||||
type (selected-window) position '(0 . 0)))
|
||||
(command (key-binding (vector type)))
|
||||
(last-input-event event))
|
||||
(should (eq command #'desktop-demo--dismiss-mouse-selection))
|
||||
(call-interactively command)
|
||||
(should-not mark-active))))))))
|
||||
|
||||
(ert-deftest ebox-playground-desktop-fast-dock-clicks-remain-controls ()
|
||||
"Single, double and triple dock click sequences never activate a region."
|
||||
(ebox-playground-desktop-test--with-preview (buffer)
|
||||
(let ((transient-mark-mode t))
|
||||
(save-window-excursion
|
||||
(set-window-buffer (selected-window) buffer)
|
||||
(dolist (label '("01 ST" "02 NT" "03 SG" "04 TM" "05 PL"))
|
||||
(dolist (type '(down-mouse-1 mouse-1 double-down-mouse-1 double-mouse-1
|
||||
triple-down-mouse-1 triple-mouse-1 drag-mouse-1
|
||||
double-drag-mouse-1 triple-drag-mouse-1))
|
||||
(let* ((position (ebox-playground-layer-test--position label))
|
||||
(event (ebox-playground-desktop-test--event
|
||||
type (selected-window) position '(0 . 0)))
|
||||
(last-input-event event))
|
||||
(goto-char position)
|
||||
(set-mark (point-min))
|
||||
(setq mark-active t)
|
||||
(run-hooks 'pre-command-hook)
|
||||
(let ((command (key-binding (vector type))))
|
||||
(should (commandp command))
|
||||
(should-not (memq command '(mouse-drag-region mouse-set-region mouse-set-point)))
|
||||
(call-interactively command))
|
||||
(should-not mark-active))))))
|
||||
(ebox-playground-layer-test--parity)))
|
||||
|
||||
(ert-deftest ebox-playground-desktop-mouse-policy-is-local-and-released ()
|
||||
"Other buffers and replacement previews retain ordinary Emacs selection."
|
||||
(ebox-playground-desktop-test--with-preview (buffer)
|
||||
(with-temp-buffer
|
||||
(should-not desktop-demo-input-mode)
|
||||
(should (eq (key-binding [down-mouse-1]) 'mouse-drag-region)))
|
||||
(ebox-playground-open-file ebox-playground-layer-test--file (buffer-name buffer))
|
||||
(should-not desktop-demo-input-mode)
|
||||
(should-not (memq #'desktop-demo--clear-mouse-mark pre-command-hook))
|
||||
(ebox-playground-open-file ebox-playground-desktop-test--file (buffer-name buffer))
|
||||
(should desktop-demo-input-mode)
|
||||
(ebox-unmount-buffer buffer)
|
||||
(should-not desktop-demo-input-mode)))
|
||||
|
||||
(ert-deftest ebox-playground-desktop-theme-adapts-all-card-and-chrome-styles ()
|
||||
"A theme toggle changes every semantic paint role without moving windows."
|
||||
(ebox-playground-desktop-test--with-preview (buffer)
|
||||
(let* ((demo ebox-playground-desktop-test--demo)
|
||||
(before (ebox-playground-desktop-test--state))
|
||||
(revision (ebox-playground-desktop-test--revision)))
|
||||
(ebox-playground-layer-test--activate "LIGHT")
|
||||
(should (eq (desktop-demo-theme demo) 'light))
|
||||
(should (= (ebox-playground-desktop-test--revision) (1+ revision)))
|
||||
(dolist (entry (desktop-demo-styles demo))
|
||||
(let ((matches (ebox-selector-query-buffer
|
||||
buffer (concat "." (symbol-name (car entry))))))
|
||||
(should matches)
|
||||
(unless (eq (car entry) 'desktop-chrome)
|
||||
(dolist (match matches)
|
||||
(let ((node (plist-get match :node)) (style (nth 2 entry)))
|
||||
(while style
|
||||
(let ((property (pop style)) (expected (pop style)))
|
||||
(unless (eq property :hover-style)
|
||||
(should (equal (ebox-get node (if (eq property :background-color)
|
||||
:bgcolor property))
|
||||
expected))))))))))
|
||||
(should (string-match-p "DARK" (buffer-string)))
|
||||
(should (member "#B9C9DE"
|
||||
(flatten-tree (get-text-property
|
||||
(ebox-playground-layer-test--position "DARK") 'mouse-face))))
|
||||
(ebox-playground-layer-test--activate "DARK")
|
||||
(should (equal before (ebox-playground-desktop-test--state)))
|
||||
(should (eq (desktop-demo-theme demo) 'dark)))))
|
||||
|
||||
(ert-deftest ebox-playground-desktop-light-theme-keeps-focus-move-and-reset ()
|
||||
"Light cards and active chrome stay light after normal window operations."
|
||||
(ebox-playground-desktop-test--with-preview (buffer 40 20)
|
||||
(ebox-playground-layer-test--activate "LIGHT")
|
||||
(ebox-playground-layer-test--activate "01 ST")
|
||||
(let* ((demo ebox-playground-desktop-test--demo)
|
||||
(position (ebox-playground-layer-test--position "01 ST"))
|
||||
(face (flatten-tree (get-text-property position 'face))))
|
||||
(should (member "#6D4AA2" face))
|
||||
(should (member "#FFFFFF" face))
|
||||
(ebox-playground-layer-test--activate "01 ST" (kbd "M-<right>"))
|
||||
(ebox-playground-layer-test--activate "RESET")
|
||||
(should (eq (desktop-demo-theme demo) 'light))
|
||||
(should (equal (desktop-demo-active demo) "desk-palette"))
|
||||
(should (member "#875270" (flatten-tree
|
||||
(get-text-property
|
||||
(ebox-playground-layer-test--position "05 PL") 'face))))
|
||||
(dolist (label '("01 ST" "02 NT" "03 SG" "04 TM" "05 PL" "DARK"))
|
||||
(should (ebox-playground-layer-test--position label))))))
|
||||
|
||||
(ert-deftest ebox-playground-desktop-failed-theme-keeps-palette-and-state ()
|
||||
"Rejected theme publication rolls back the complete palette and state."
|
||||
(ebox-playground-desktop-test--with-preview (buffer)
|
||||
(dolist (failure-step '(text client-state))
|
||||
(let ((before (buffer-string))
|
||||
(state (ebox-playground-desktop-test--state))
|
||||
(tp--surface-publication-step-function
|
||||
(lambda (step _surface)
|
||||
(when (eq step failure-step) (error "Reject theme")))))
|
||||
(should-error (ebox-playground-layer-test--activate "LIGHT"))
|
||||
(should (equal state (ebox-playground-desktop-test--state)))
|
||||
(should (equal-including-properties before (buffer-string)))))
|
||||
(ebox-playground-layer-test--activate "LIGHT")))
|
||||
|
||||
(ert-deftest ebox-playground-desktop-light-palette-has-pale-cards-and-dark-ink ()
|
||||
"Every light card is pale and its body/caption text has useful contrast."
|
||||
(ebox-playground-desktop-test--with-preview (buffer)
|
||||
(let ((styles (desktop-demo-styles ebox-playground-desktop-test--demo)))
|
||||
(cl-labels
|
||||
((light (role) (nth 2 (assq role styles)))
|
||||
(luminance (hex)
|
||||
(cl-loop for start in '(1 3 5) for weight in '(0.2126 0.7152 0.0722)
|
||||
for value = (/ (string-to-number (substring hex start (+ start 2)) 16) 255.0)
|
||||
sum (* weight (if (<= value 0.04045) (/ value 12.92)
|
||||
(expt (/ (+ value 0.055) 1.055) 2.4)))))
|
||||
(contrast (fg bg)
|
||||
(let ((a (luminance fg)) (b (luminance bg)))
|
||||
(/ (+ (max a b) 0.05) (+ (min a b) 0.05)))))
|
||||
(dolist (role '(desktop-root desktop-workspace desktop-studio desktop-notes
|
||||
desktop-signal desktop-terminal desktop-palette))
|
||||
(let ((style (light role)))
|
||||
(should (> (luminance (plist-get style :background-color)) 0.7))
|
||||
(when (plist-get style :color)
|
||||
(should (> (contrast (plist-get style :color)
|
||||
(plist-get style :background-color)) 4.5)))))
|
||||
(dolist (pair '((desktop-studio-muted . desktop-studio)
|
||||
(desktop-notes-caption . desktop-notes)
|
||||
(desktop-signal-caption . desktop-signal)
|
||||
(desktop-terminal-muted . desktop-terminal)
|
||||
(desktop-palette-caption . desktop-palette)))
|
||||
(should (> (contrast (plist-get (light (car pair)) :color)
|
||||
(plist-get (light (cdr pair)) :background-color)) 4.5)))))))
|
||||
|
||||
(ert-deftest ebox-playground-desktop-previews-have-independent-themes ()
|
||||
"Changing one desktop palette cannot recolor a second preview."
|
||||
(ebox-playground-desktop-test--with-preview (first)
|
||||
(let ((first-demo ebox-playground-desktop-test--demo))
|
||||
(ebox-playground-desktop-test--with-preview (second)
|
||||
(let ((before (buffer-string)))
|
||||
(with-current-buffer first
|
||||
(desktop-demo-toggle-theme first-demo)
|
||||
(ebox-playground-layer-test--parity))
|
||||
(should (equal-including-properties before (buffer-string)))
|
||||
(should (eq (desktop-demo-theme ebox-playground-desktop-test--demo) 'dark))
|
||||
(should (eq (desktop-demo-theme first-demo) 'light)))))))
|
||||
|
||||
(ert-deftest ebox-playground-desktop-repeated-keyboard-nudges-retain-dock-binding ()
|
||||
"Repeated arrow commands keep their native dock binding without repositioning."
|
||||
(dolist (key '("M-<right>" "M-<left>" "M-<up>" "M-<down>"))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user