diff --git a/crates/sylpheed-formats/examples/screen_layout.rs b/crates/sylpheed-formats/examples/screen_layout.rs index 99c67db..4009fe6 100644 --- a/crates/sylpheed-formats/examples/screen_layout.rs +++ b/crates/sylpheed-formats/examples/screen_layout.rs @@ -54,7 +54,8 @@ fn main() { // Placement region: groups of (u32 element index, u32 keyframe count) then // `count` 40-byte keyframes; the X/Y sit 12 bytes into the scale/tint block. let mut pos = 0x20 + count * 60; - let mut placements: Vec> = vec![Vec::new(); count]; + // X/Y are SIGNED: off-screen animation starts are negative (e.g. -516). + let mut placements: Vec> = vec![Vec::new(); count]; for _ in 0..count { if pos + 8 > bytes.len() { break } let idx = be32(&bytes, pos) as usize; @@ -65,7 +66,7 @@ fn main() { for k in 0..frames { let blk = first + k * 40; if blk + 20 > bytes.len() { break } - group.push((be32(&bytes, blk + 12), be32(&bytes, blk + 16))); + group.push((be32(&bytes, blk + 12) as i32, be32(&bytes, blk + 16) as i32, be32(&bytes, blk + 20))); } placements[idx] = group; pos = first + frames * 40 - 20; @@ -76,10 +77,25 @@ fn main() { for i in 0..count { let (parent, kind, px, py) = meta[i]; let p = &placements[i]; - let shown = match (p.first(), p.last()) { - (Some(f), Some(l)) if p.len() > 1 && f != l => format!("{:?} → {:?}", f, l), - (Some(f), _) => format!("{:?}", f), - _ => "—".into(), + // A group is an in → hold → out animation, so neither the first nor the + // last keyframe is where the element sits: report the MAX-DWELL one + // (longest gap to the next keyframe's time). + let shown = if p.is_empty() { + "—".into() + } else if p.len() == 1 { + format!("({},{})", p[0].0, p[0].1) + } else { + let mut best = (0usize, 0u32); + for k in 0..p.len() - 1 { + let d = p[k + 1].2.saturating_sub(p[k].2); + if d > best.1 { best = (k, d) } + } + let r = p[best.0]; + format!( + "rest ({},{}) t={}..{} [{}]", + r.0, r.1, r.2, p[best.0 + 1].2, + p.iter().map(|(x, y, t)| format!("{t}:{x},{y}")).collect::>().join(" ") + ) }; println!( "{:<3} {:<30} {:>7} {:>8} {:>12} {:>4} {}", diff --git a/docs/re/captures/arsenal-main-screen-layout.txt b/docs/re/captures/arsenal-main-screen-layout.txt index b3d68b0..1fbeac2 100644 --- a/docs/re/captures/arsenal-main-screen-layout.txt +++ b/docs/re/captures/arsenal-main-screen-layout.txt @@ -1,25 +1,50 @@ +=== eng\prmain_scr.prt === 23 elements # element parent kind pivot kf placement -0 preff01.t32 - 0x0 (164,156) 5 (256, 214) -1 preff02.t32 - 0x0 (155,175) 7 (305, 240) -2 preff03.t32 - 0x0 (155,175) 7 (225, 150) -3 preff04.t32 - 0x0 (247,237) 6 (173, 133) -4 prwinbase.t32 - 0x0 (136,130) 5 (284, 240) -5 prbtn1.rat - 0x3002 (28,14) 5 (242, 166) -6 prbtn2.rat - 0x3002 (43,14) 5 (242, 220) -7 prbtn3.rat - 0x3002 (58,14) 5 (242, 276) -8 prbtn4.rat - 0x3002 (89,14) 5 (242, 331) -9 prbtn5.rat - 0x3002 (89,14) 5 (242, 385) -10 prbtn6.rat - 0x3002 (104,14) 5 (242, 441) -11 prbtn7.rat - 0x3002 (58,14) 5 (242, 496) -12 prbtn8.rat - 0x3002 (30,14) 5 (242, 551) -13 prexp1.t32 - 0x0 (277,30) 8 (726, 143) → (1286, 143) -14 prexp1a.t32 13 0x1 (277,30) 3 (1126, 143) -15 prexp3.t32 - 0x0 (205,5) 5 (726, 381) -16 prmsg.t32 - 0x0 (330,19) 5 (151, 645) -17 prexp3.t32 - 0x4 (205,5) 5 (726, 415) -18 prexp3.t32 - 0x4 (205,5) 5 (726, 449) -19 prexp3.t32 - 0x4 (205,5) 5 (726, 483) -20 prexp3.t32 - 0x4 (205,5) 5 (726, 517) -21 prexp3.t32 - 0x4 (205,5) 5 (726, 551) -22 prexp3.t32 - 0x4 (205,5) 5 (726, 585) +0 preff01.t32 - 0x0 (164,156) 5 rest (256,214) t=6..22 [6:256,214 22:256,214 31:256,214 42:256,214 1:256,214] +1 preff02.t32 - 0x0 (155,175) 7 rest (156,121) t=8..37 [4:305,240 6:193,150 7:165,128 8:156,121 37:155,120 44:155,120 2:305,240] +2 preff03.t32 - 0x0 (155,175) 7 rest (374,269) t=8..37 [4:225,150 6:337,240 7:365,262 8:374,269 37:375,270 44:375,270 3:225,150] +3 preff04.t32 - 0x0 (247,237) 6 rest (173,133) t=8..37 [4:173,133 6:173,133 8:173,133 37:173,133 44:173,133 4:173,133] +4 prwinbase.t32 - 0x0 (136,130) 5 rest (284,240) t=14..35 [6:284,240 14:284,240 35:284,240 43:284,240 5:284,240] +5 prbtn1.rat - 0x3002 (28,14) 5 rest (242,166) t=16..33 [10:242,166 16:242,166 33:242,166 37:242,166 6:242,166] +6 prbtn2.rat - 0x3002 (43,14) 5 rest (242,220) t=17..33 [11:242,220 17:242,220 33:242,220 37:242,220 7:242,220] +7 prbtn3.rat - 0x3002 (58,14) 5 rest (242,276) t=18..33 [12:242,276 18:242,276 33:242,276 37:242,276 8:242,276] +8 prbtn4.rat - 0x3002 (89,14) 5 rest (242,331) t=19..33 [13:242,331 19:242,331 33:242,331 37:242,331 9:242,331] +9 prbtn5.rat - 0x3002 (89,14) 5 rest (242,385) t=20..33 [14:242,385 20:242,385 33:242,385 37:242,385 10:242,385] +10 prbtn6.rat - 0x3002 (104,14) 5 rest (242,441) t=21..33 [15:242,441 21:242,441 33:242,441 37:242,441 11:242,441] +11 prbtn7.rat - 0x3002 (58,14) 5 rest (242,496) t=22..33 [16:242,496 22:242,496 33:242,496 37:242,496 12:242,496] +12 prbtn8.rat - 0x3002 (30,14) 5 rest (242,551) t=23..33 [17:242,551 23:242,551 33:242,551 37:242,551 13:242,551] +13 prexp1.t32 - 0x0 (277,30) 8 rest (726,143) t=31..37 [21:726,143 25:1286,143 27:866,143 28:756,143 29:731,143 31:726,143 37:726,143 14:1286,143] +14 prexp1a.t32 13 0x1 (277,30) 3 rest (1126,143) t=31..37 [31:1126,143 37:1126,143 15:1126,143] +15 prexp3.t32 - 0x0 (205,5) 5 rest (726,381) t=10..29 [10:726,381 29:726,381 31:726,381 39:726,381 16:726,381] +16 prmsg.t32 - 0x0 (330,19) 5 rest (151,645) t=21..29 [21:151,645 29:151,645 31:151,645 37:151,645 17:151,645] +17 prexp3.t32 - 0x4 (205,5) 5 rest (726,415) t=10..29 [10:726,415 29:726,415 31:726,415 39:726,415 18:726,415] +18 prexp3.t32 - 0x4 (205,5) 5 rest (726,449) t=10..29 [10:726,449 29:726,449 31:726,449 39:726,449 19:726,449] +19 prexp3.t32 - 0x4 (205,5) 5 rest (726,483) t=10..29 [10:726,483 29:726,483 31:726,483 39:726,483 20:726,483] +20 prexp3.t32 - 0x4 (205,5) 5 rest (726,517) t=10..29 [10:726,517 29:726,517 31:726,517 39:726,517 21:726,517] +21 prexp3.t32 - 0x4 (205,5) 5 rest (726,551) t=10..29 [10:726,551 29:726,551 31:726,551 39:726,551 22:726,551] +22 prexp3.t32 - 0x4 (205,5) 5 rest (726,585) t=39..1869640736 [10:726,585 29:726,585 31:726,585 39:726,585 1869640736:726,585] +=== eng\prselect_scr.prt === +8 elements +# element parent kind pivot kf placement +0 prselect_win1.t32 - 0x0 (256,200) 10 rest (127,155) t=8..23 [4:-516,155 6:-71,155 7:81,155 8:127,155 23:134,155 24:134,155 25:127,155 27:81,155 31:-71,155 1:-516,155] +1 prselect_win2.t32 0 0x1 (256,200) 1 (135,560) +2 prselect_win1eff.t32 0 0x1 (256,200) 5 rest (71,92) t=2..14 [2:71,92 14:71,92 21:71,92 27:71,92 3:71,92] +3 prselect_win2eff.t32 0 0x1 (256,200) 5 rest (71,499) t=2..14 [2:71,499 14:71,499 21:71,499 27:71,499 4:71,499] +4 prselect_sbar.sbo 0 0x1 (256,200) 1 (614,172) +5 prselect_type_line.t32 - 0x0 (260,24) 5 rest (123,142) t=14..21 [8:123,142 14:123,142 21:123,142 25:123,142 6:123,142] +6 prselect_msg.t32 - 0x0 (468,19) 5 rest (151,645) t=11..19 [11:151,645 19:151,645 21:151,645 27:151,645 7:151,645] +7 prselect_msgbtn1.t32 - 0x2 (128,19) 5 rest (809,645) t=27..1869640736 [11:809,645 19:809,645 21:809,645 27:809,645 1869640736:809,645] +=== eng\prselect_win3.prt === +2 elements +# element parent kind pivot kf placement +0 prselect_win3.t32 - 0x0 (245,300) 4 rest (704,39) t=10..16 [8:704,39 10:704,39 16:704,39 1:704,39] +1 prselect_win3eff.t32 - 0x0 (309,352) 4 rest (640,0) t=16..1869640736 [8:640,0 10:640,0 16:640,0 1869640736:640,0] +=== eng\prtitle.prt === +5 elements +# element parent kind pivot kf placement +0 preff11.t32 - 0x0 (221,6) 6 rest (-160,82) t=16..35 [12:-440,82 14:-440,82 16:-160,82 35:0,82 41:0,82 1:-440,82] +1 preff12.t32 - 0x0 (75,3) 5 rest (0,72) t=20..34 [14:0,72 20:0,72 34:0,72 38:0,72 2:0,72] +2 preff13.t32 - 0x0 (53,3) 5 rest (407,78) t=22..33 [16:407,78 22:407,78 33:407,78 37:407,78 3:407,78] +3 preff14.t32 - 0x0 (52,3) 5 rest (427,68) t=24..32 [18:427,68 24:427,68 32:427,68 36:427,68 4:427,68] +4 prtitle.t32 - 0x0 (94,35) 7 rest (162,26) t=37..1869640736 [20:142,26 23:142,26 25:157,26 26:161,26 31:162,26 37:162,26 1869640736:142,26] diff --git a/docs/re/captures/pause-tutorial-screen-layout.txt b/docs/re/captures/pause-tutorial-screen-layout.txt index 6930e32..07c9547 100644 --- a/docs/re/captures/pause-tutorial-screen-layout.txt +++ b/docs/re/captures/pause-tutorial-screen-layout.txt @@ -1,13 +1,13 @@ 11 elements # element parent kind pivot kf placement -0 pgp_ttrl_eff11.t32 - 0x0 (34,33) 7 (603, 121) → (493, 121) -1 pgp_ttrl_eff12.t32 - 0x0 (34,33) 7 (609, 121) → (719, 121) -2 pgp_ttrl_eff10.t32 - 0x0 (204,60) 5 (436, 94) -3 pgp_ttrl_eff22.t32 - 0x0 (133,130) 5 (480, 225) → (490, 225) -4 pgp_ttrl_eff23.t32 - 0x0 (138,130) 5 (524, 271) → (514, 271) -5 pgp_ttrl_eff21.t32 - 0x0 (214,180) 5 (426, 198) -6 pgp_ttrl_title.rat - 0x0 (101,36) 6 (540, 119) -7 pgp_ttrl_btn10.rat - 0x3002 (43,21) 5 (546, 288) -8 pgp_ttrl_btn11.rat - 0x3002 (86,22) 5 (546, 358) -9 pgp_ttrl_btn12.rat - 0x3002 (110,21) 5 (546, 428) -10 pgp_ttrl_msg.t32 - 0x0 (190,19) 5 (451, 545) +0 pgp_ttrl_eff11.t32 - 0x0 (34,33) 7 rest (470,121) t=9..25 [3:603,121 6:603,121 8:503,121 9:470,121 25:463,121 30:463,121 1:493,121] +1 pgp_ttrl_eff12.t32 - 0x0 (34,33) 7 rest (742,121) t=9..25 [3:609,121 6:609,121 8:709,121 9:742,121 25:749,121 30:749,121 2:719,121] +2 pgp_ttrl_eff10.t32 - 0x0 (204,60) 5 rest (436,94) t=14..23 [8:436,94 14:436,94 23:436,94 30:436,94 3:436,94] +3 pgp_ttrl_eff22.t32 - 0x0 (133,130) 5 rest (480,225) t=11..25 [5:480,225 11:480,225 25:460,225 30:460,225 4:490,225] +4 pgp_ttrl_eff23.t32 - 0x0 (138,130) 5 rest (524,271) t=11..25 [5:524,271 11:524,271 25:544,271 30:544,271 5:514,271] +5 pgp_ttrl_eff21.t32 - 0x0 (214,180) 5 rest (426,198) t=9..21 [9:426,198 21:426,198 23:426,198 30:426,198 6:426,198] +6 pgp_ttrl_title.rat - 0x0 (101,36) 6 rest (540,119) t=13..23 [5:540,119 13:540,119 23:540,119 28:540,119 30:540,119 7:540,119] +7 pgp_ttrl_btn10.rat - 0x3002 (43,21) 5 rest (546,288) t=15..23 [9:546,288 15:546,288 23:546,288 26:546,288 8:546,288] +8 pgp_ttrl_btn11.rat - 0x3002 (86,22) 5 rest (546,358) t=11..17 [11:546,358 17:546,358 23:546,358 26:546,358 9:546,358] +9 pgp_ttrl_btn12.rat - 0x3002 (110,21) 5 rest (546,428) t=13..19 [13:546,428 19:546,428 23:546,428 26:546,428 10:546,428] +10 pgp_ttrl_msg.t32 - 0x0 (190,19) 5 rest (451,545) t=28..1869640736 [16:451,545 21:451,545 23:451,545 28:451,545 1869640736:451,545] diff --git a/docs/re/structures/ui-rat-layout.md b/docs/re/structures/ui-rat-layout.md index fdab7e7..d0f32bd 100644 --- a/docs/re/structures/ui-rat-layout.md +++ b/docs/re/structures/ui-rat-layout.md @@ -202,17 +202,33 @@ recording them because a static-only reading would have shipped them: ``` group header: u32 element index (0,1,2… — the correspondence is stated, not inferred) u32 keyframe count - then `count` keyframes, 40 bytes apart, each holding the familiar block: + then `count` keyframes, 40 bytes apart, each holding: u32 scale X = 100 u32 scale Y = 100 u32 tint = 0xffffffff - u32 X u32 Y (+ a trailing time field) + i32 X i32 Y ← SIGNED + u32 time u32 flags/terminator ``` + **Three things here are easy to get wrong, and were:** + + - **X and Y are signed.** Off-screen animation starts are negative — the Arsenal's + weapon-list window begins at **X = −516**. Read as unsigned it is 4 294 966 780, + which a naïve implementation would happily draw four billion pixels to the right. + - **The trailing word is a time**, and a group is an **in → hold → out** + animation. `prselect_win1` runs `t=4:−516 → 6:−71 → 7:81 → 8:127 → 23:134 → + 24:134 → 25:127 → 27:81 → 31:−71 → 1:−516`. + - **So neither the first nor the last keyframe is where the element sits.** Both + are off-screen for an animated element. The resting position is the + **max-dwell** keyframe — the one with the longest gap to the next time — which + for that window is **(127,155)…(134,155)**, matching where the list panel + actually appears. `screen_layout.rs` reports that, not `final`. + For the tutorial pause bundle this yields 11 groups for 11 elements, and every group's header index and count match the blocks actually present. The values are self-evidently right: the three menu buttons sit at X=546, **70 px apart** - (288 / 358 / 428), the title at (540,119), the message at (451,545), and the - `eff*` sprites carry multi-position fly-ins. + (288 / 358 / 428) — static, every keyframe identical, which is why their reading + was unaffected by the first/last mistake above — the title at (540,119), the + message at (451,545), and the `eff*` sprites carry multi-position fly-ins. **Cross-checked against the records themselves:** `pgp_ttrl_btn10.rat` places its sprite at **(546,288)** — identical to its inline group. So the inline region is