fix(renderer): keep transparent decoration layers out of the way of clicks
Two carousel templates stack a full-bleed transparent shell (washi tape, punch holes, film sprockets) in front of their content. Every click over the board landed on that shell instead of the text behind it. The engine half is the jian bump: a container that paints nothing no longer claims its own body in the hit-test. The template half marks those shells `locked`, so the shell is unselectable as a layer while the marks inside it stay individually selectable — dragging a piece of tape no longer drags the whole layer, and a marquee no longer nets the board. Both templates are regenerated output, so they also carry the row wrap their generators gained in the same pass. Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
This commit is contained in:
parent
e6013d71da
commit
3a8c154739
|
|
@ -60,6 +60,7 @@
|
|||
"height": 1440,
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -1844,6 +1845,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -1929,6 +1931,7 @@
|
|||
"height": 1440,
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -3726,6 +3729,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -3811,6 +3815,7 @@
|
|||
"height": 1440,
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -5935,6 +5940,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -6020,6 +6026,7 @@
|
|||
"height": 1440,
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -7817,6 +7824,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -7875,8 +7883,8 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"x": 3600,
|
||||
"y": 0
|
||||
"x": 0,
|
||||
"y": 1800
|
||||
},
|
||||
{
|
||||
"type": "frame",
|
||||
|
|
@ -7902,6 +7910,7 @@
|
|||
"height": 1440,
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -9881,6 +9890,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -9939,8 +9949,8 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"x": 4800,
|
||||
"y": 0
|
||||
"x": 1200,
|
||||
"y": 1800
|
||||
},
|
||||
{
|
||||
"type": "frame",
|
||||
|
|
@ -9966,6 +9976,7 @@
|
|||
"height": 1440,
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -11626,6 +11637,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -11684,8 +11696,8 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"x": 6000,
|
||||
"y": 0
|
||||
"x": 2400,
|
||||
"y": 1800
|
||||
},
|
||||
{
|
||||
"type": "frame",
|
||||
|
|
@ -11711,6 +11723,7 @@
|
|||
"height": 1440,
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -13612,6 +13625,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
|
|
@ -13670,8 +13684,8 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"x": 7200,
|
||||
"y": 0
|
||||
"x": 0,
|
||||
"y": 3600
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "path",
|
||||
|
|
@ -480,6 +481,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "ellipse",
|
||||
|
|
@ -654,6 +656,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "path",
|
||||
|
|
@ -1310,6 +1313,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "ellipse",
|
||||
|
|
@ -1484,6 +1488,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "path",
|
||||
|
|
@ -2019,6 +2024,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "ellipse",
|
||||
|
|
@ -2193,6 +2199,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "path",
|
||||
|
|
@ -2874,6 +2881,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "ellipse",
|
||||
|
|
@ -3022,8 +3030,8 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"x": 3600,
|
||||
"y": 0
|
||||
"x": 0,
|
||||
"y": 1800
|
||||
},
|
||||
{
|
||||
"type": "frame",
|
||||
|
|
@ -3048,6 +3056,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "path",
|
||||
|
|
@ -3474,6 +3483,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "ellipse",
|
||||
|
|
@ -3622,8 +3632,8 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"x": 4800,
|
||||
"y": 0
|
||||
"x": 1200,
|
||||
"y": 1800
|
||||
},
|
||||
{
|
||||
"type": "frame",
|
||||
|
|
@ -3648,6 +3658,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "path",
|
||||
|
|
@ -4258,6 +4269,7 @@
|
|||
"height": "fill_container",
|
||||
"layout": "none",
|
||||
"fill": [],
|
||||
"locked": true,
|
||||
"children": [
|
||||
{
|
||||
"type": "ellipse",
|
||||
|
|
@ -4406,8 +4418,8 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"x": 6000,
|
||||
"y": 0
|
||||
"x": 2400,
|
||||
"y": 1800
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,13 @@ CJK = "Noto Sans SC"
|
|||
NUM = "DM Mono"
|
||||
|
||||
W, H, GAP = 1080, 1440, 120
|
||||
|
||||
# 3 板一行 —— 与 deck 体系(deckkit.BOARDS_PER_ROW)同一约定:多板模板在画布上
|
||||
# 分行铺开,而不是拖成一长排。行间距比列间距多 240 不是手滑:画布在帧上方以
|
||||
# **屏幕空间**固定偏移画帧名,缩到能整屏看时 120 文档像素只剩十几个屏幕像素,
|
||||
# 第二行的帧名会压到上一行的板上。
|
||||
BOARDS_PER_ROW = 3
|
||||
ROW_GAP = GAP + 240
|
||||
BORDER = 24 # 相纸白边
|
||||
EDGE = 80 - BORDER # 片窗内的左右内边距,合计仍是 80
|
||||
TOP, BOT = 96 - BORDER, 128 - BORDER
|
||||
|
|
@ -241,7 +248,13 @@ def footer(edge_code):
|
|||
|
||||
|
||||
def board(page, name, main, edge_code):
|
||||
"""一板。外壳是相纸白,白边之内才是片基 —— 白边是本套的第一识别信号。"""
|
||||
"""一板。外壳是相纸白,白边之内才是片基 —— 白边是本套的第一识别信号。
|
||||
|
||||
齿孔层与色偏层都上 `locked`:两者都是铺满整板的壳子,自己一寸不画(墨
|
||||
在里面那 24 个孔 / 两条色带上)。齿孔层还压在正文之上,不锁的话它自身
|
||||
就是一块盖住全板的透明板。locked 让壳子不可选而壳内的孔照常可选
|
||||
(hit_test_walk 的 locked 判定在子节点遍历之后)。
|
||||
"""
|
||||
content = frame(ids, f"{name} · 内容", width="fill_container",
|
||||
height="fill_container", layout="vertical",
|
||||
padding=[TOP, EDGE, BOT, EDGE], gap=0,
|
||||
|
|
@ -253,19 +266,20 @@ def board(page, name, main, edge_code):
|
|||
fill=solid("$c-bg"), clipContent=True)
|
||||
# 装饰(色偏)最后 —— jian 里 index 0 最上,写反了会盖住正文。
|
||||
cast = frame(ids, f"{name} · 色偏", width="fill_container",
|
||||
height="fill_container", layout="none", fill=[])
|
||||
height="fill_container", layout="none", fill=[],
|
||||
locked=True)
|
||||
cast["children"] = colour_cast()
|
||||
gate["children"] = [content, cast]
|
||||
|
||||
shell = frame(ids, f"{page:02d} {name}", width=W, height=H, layout="none",
|
||||
fill=solid("$c-print"), padding=BORDER, clipContent=True)
|
||||
holes = frame(ids, f"{name} · 齿孔", width=W, height=H, layout="none",
|
||||
fill=[])
|
||||
fill=[], locked=True)
|
||||
holes["children"] = sprockets()
|
||||
holes["x"], holes["y"] = -BORDER, -BORDER
|
||||
shell["children"] = [holes, gate]
|
||||
shell["x"] = (page - 1) * (W + GAP)
|
||||
shell["y"] = 0
|
||||
shell["x"] = ((page - 1) % BOARDS_PER_ROW) * (W + GAP)
|
||||
shell["y"] = ((page - 1) // BOARDS_PER_ROW) * (H + ROW_GAP)
|
||||
return shell
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,13 @@ CJK = "Noto Sans SC"
|
|||
NUM = "Inter"
|
||||
|
||||
W, H, GAP = 1080, 1440, 120
|
||||
|
||||
# 3 板一行 —— 与 deck 体系(deckkit.BOARDS_PER_ROW)同一约定:多板模板在画布上
|
||||
# 分行铺开,而不是拖成一长排。行间距比列间距多 240 不是手滑:画布在帧上方以
|
||||
# **屏幕空间**固定偏移画帧名,缩到能整屏看时 120 文档像素只剩十几个屏幕像素,
|
||||
# 第二行的帧名会压到上一行的板上。
|
||||
BOARDS_PER_ROW = 3
|
||||
ROW_GAP = GAP + 240
|
||||
EDGE = 80
|
||||
RING_GUTTER = 56 # 活页孔占掉的左侧宽度
|
||||
TEXT_EDGE = EDGE + RING_GUTTER
|
||||
|
|
@ -265,6 +272,11 @@ def board(page, name, main, tapes):
|
|||
jian 的兄弟顺序是 index 0 最上(canvas_viewport_paint_mask 反着遍历)。
|
||||
胶带层用 group:group 不是图片投放目标(image_drop.rs 不匹配 Group),
|
||||
所以它盖在整板上也不会截走用户拖进来的图。
|
||||
|
||||
两个装饰层都上 `locked`:它们是 fill_container 的满幅壳子,压在正文之
|
||||
上,但自己一寸也不画(真正的墨在里面那几条胶带 / 六个孔上)。locked 让
|
||||
壳子自身不可选,壳内的胶带和孔照常可选(hit_test_walk 的 locked 判定在
|
||||
子节点遍历之后),于是拖动装饰不会拽走整层,框选也不会一网兜住整板。
|
||||
"""
|
||||
content = frame(ids, f"{name} · 内容", width="fill_container",
|
||||
height="fill_container", layout="vertical",
|
||||
|
|
@ -273,18 +285,20 @@ def board(page, name, main, tapes):
|
|||
content["children"] = [header(page), main, footer()]
|
||||
|
||||
tape_layer = group(ids, f"{name} · 胶带", width="fill_container",
|
||||
height="fill_container", layout="none", fill=[])
|
||||
height="fill_container", layout="none", fill=[],
|
||||
locked=True)
|
||||
tape_layer["children"] = tapes
|
||||
|
||||
holes = frame(ids, f"{name} · 活页孔", width="fill_container",
|
||||
height="fill_container", layout="none", fill=[])
|
||||
height="fill_container", layout="none", fill=[],
|
||||
locked=True)
|
||||
holes["children"] = ring_holes()
|
||||
|
||||
shell = frame(ids, f"{page:02d} {name}", width=W, height=H, layout="none",
|
||||
fill=solid("$c-bg"), clipContent=True)
|
||||
shell["children"] = [tape_layer, content, holes]
|
||||
shell["x"] = (page - 1) * (W + GAP)
|
||||
shell["y"] = 0
|
||||
shell["x"] = ((page - 1) % BOARDS_PER_ROW) * (W + GAP)
|
||||
shell["y"] = ((page - 1) // BOARDS_PER_ROW) * (H + ROW_GAP)
|
||||
return shell
|
||||
|
||||
|
||||
|
|
|
|||
2
vendor/jian
vendored
2
vendor/jian
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 453bd70b646417e58f0d5c9a51594e27d399d849
|
||||
Subproject commit 18691c42169f59374d58d13065fc606fa6c39c24
|
||||
Loading…
Reference in a new issue