pets get their action bar, macros arrive, and hunters draw the bow
- a hunter's or warlock's pet has its action bar now: attack, follow, stay, the pet's own spells with cooldowns and autocast sparkles - the macro system lands: the macro window, the icon chooser, /cast and /macro, and macros dragged onto the action bar - hunter shots look right at last: the bow draws and releases on the shot, and the arrow lays a spark trail its whole flight - the options window re-dresses in 1.12's own art with the classic dialog look, and gets a working search box and clickable steppers Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -198,25 +198,7 @@ impl Loader<'_> {
|
||||
) {
|
||||
let color = children_named(region, "Color").next().map(color_of);
|
||||
if is_texture {
|
||||
if let Some(atlas) = region.attr("atlas") {
|
||||
// `atlas="member"` (decision 0950): the Era dialect's texture reference — one
|
||||
// SetAtlas resolves sheet + UV sub-rect (+ nominal size with `useAtlasSize`)
|
||||
// through the app-pushed manifest table; `file=` remains the 1.12 MPQ path.
|
||||
self.call_region(
|
||||
region_wrapper,
|
||||
"SetAtlas",
|
||||
(atlas.to_string(), region.attr_bool("useAtlasSize")),
|
||||
dbg,
|
||||
);
|
||||
if let Some(c) = color {
|
||||
self.call_region(
|
||||
region_wrapper,
|
||||
"SetVertexColor",
|
||||
(c[0], c[1], c[2], c[3]),
|
||||
dbg,
|
||||
);
|
||||
}
|
||||
} else if let Some(file) = region.attr("file") {
|
||||
if let Some(file) = region.attr("file") {
|
||||
self.call_region(region_wrapper, "SetTexture", file.to_string(), dbg);
|
||||
if let Some(c) = color {
|
||||
// A texture with both a file and a <Color> is a tint (vertex color).
|
||||
|
||||
@@ -1000,85 +1000,4 @@ mod region_template_tests {
|
||||
);
|
||||
assert_eq!(s.eval::<String>("return Label:GetText()").unwrap(), "hello");
|
||||
}
|
||||
|
||||
/// `atlas=` on a Button/CheckButton state texture and on a Slider `<ThumbTexture>` — the Era
|
||||
/// dialect (0950) extended to the widget texture paths (0957): the slot is created empty and
|
||||
/// resolved through SetAtlas, so the region answers GetAtlas and (with `useAtlasSize`) wears
|
||||
/// the member's nominal size. The byte-verified 1.12 loader tables know only file=/<Color>.
|
||||
#[test]
|
||||
fn state_textures_and_the_thumb_take_the_atlas_attr() {
|
||||
let mut s = UiScript::new().unwrap();
|
||||
s.set_screen_size(800.0, 600.0);
|
||||
s.set_era_atlases([
|
||||
(
|
||||
"checkbox-minimal".to_string(),
|
||||
crate::script::EraAtlasEntry {
|
||||
file: "era:textures/4614134.blp".to_string(),
|
||||
uv: [1.0 / 64.0, 31.0 / 64.0, 1.0 / 64.0, 30.0 / 64.0],
|
||||
size: [30.0, 29.0],
|
||||
},
|
||||
),
|
||||
(
|
||||
"checkmark-minimal".to_string(),
|
||||
crate::script::EraAtlasEntry {
|
||||
file: "era:textures/4614134.blp".to_string(),
|
||||
uv: [1.0 / 64.0, 31.0 / 64.0, 32.0 / 64.0, 61.0 / 64.0],
|
||||
size: [30.0, 29.0],
|
||||
},
|
||||
),
|
||||
(
|
||||
"minimal_sliderbar_button".to_string(),
|
||||
crate::script::EraAtlasEntry {
|
||||
file: "era:textures/4567914.blp".to_string(),
|
||||
uv: [1.0 / 128.0, 21.0 / 128.0, 20.0 / 128.0, 39.0 / 128.0],
|
||||
size: [20.0, 19.0],
|
||||
},
|
||||
),
|
||||
]);
|
||||
let doc = parse(
|
||||
r#"<Ui>
|
||||
<CheckButton name="Box">
|
||||
<Size><AbsDimension x="30" y="29"/></Size>
|
||||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||||
<NormalTexture atlas="checkbox-minimal"/>
|
||||
<CheckedTexture atlas="checkmark-minimal"/>
|
||||
</CheckButton>
|
||||
<Slider name="Bar" orientation="HORIZONTAL" minValue="0" maxValue="1">
|
||||
<Size><AbsDimension x="200" y="19"/></Size>
|
||||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||||
<ThumbTexture atlas="minimal_sliderbar_button" useAtlasSize="true"/>
|
||||
</Slider>
|
||||
</Ui>"#,
|
||||
)
|
||||
.expect("valid FrameXML");
|
||||
let report = load(&s, &doc, &no_files);
|
||||
assert!(report.errors.is_empty(), "errors: {:?}", report.errors);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return Box:GetNormalTexture():GetAtlas()")
|
||||
.unwrap(),
|
||||
"checkbox-minimal"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return Box:GetCheckedTexture():GetAtlas()")
|
||||
.unwrap(),
|
||||
"checkmark-minimal"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<String>("return Bar:GetThumbTexture():GetAtlas()")
|
||||
.unwrap(),
|
||||
"minimal_sliderbar_button"
|
||||
);
|
||||
// useAtlasSize rode along — the thumb wears the member's nominal 20×19 (what the
|
||||
// engine's thumb-travel math reads).
|
||||
assert_eq!(
|
||||
s.eval::<f64>("return Bar:GetThumbTexture():GetWidth()")
|
||||
.unwrap(),
|
||||
20.0
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<f64>("return Bar:GetThumbTexture():GetHeight()")
|
||||
.unwrap(),
|
||||
19.0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,24 +85,20 @@ impl Loader<'_> {
|
||||
this.call(wrapper, method, file.to_string(), dbg);
|
||||
} else if let Some(c) = children_named(t, "Color").next().map(color_of) {
|
||||
this.call(wrapper, method, (c[0], c[1], c[2], c[3]), dbg);
|
||||
} else if t.attr("atlas").is_some() {
|
||||
// `atlas=` (decision 0950, the Era dialect — same seam as a `<Layers>`
|
||||
// texture's): the byte-verified 1.12 table knows only file=/<Color>, so the
|
||||
// setter first creates the slot empty and SetAtlas below resolves it.
|
||||
} else if t.name().is_some() {
|
||||
// A NAMED state texture with no art of its own — `<NormalTexture
|
||||
// name="$parentIcon">` on the ref's own MacroFrameButtonTemplate, whose art
|
||||
// arrives later through `SetTexture`. The setter is what MATERIALIZES the
|
||||
// slot's region, so without this call the getter below finds nothing and the
|
||||
// name never publishes: `getglobal("MacroButton1Icon")` would be nil and the
|
||||
// window's whole Update would die on it. `""` is the live API's own blank form
|
||||
// (`set_slot_texture`'s empty-string arm), so this creates without painting.
|
||||
this.call(wrapper, method, String::new(), dbg);
|
||||
}
|
||||
// alphaMode / <Size> / <Anchors> / <TexCoords> apply to the region the setter just
|
||||
// created — fetch it back through the matching getter and use the region methods.
|
||||
let getter = method.replacen("Set", "Get", 1);
|
||||
if let Ok(region) = wrapper.call_method::<Table>(getter.as_str(), ()) {
|
||||
if let Some(atlas) = t.attr("atlas") {
|
||||
this.call_region(
|
||||
®ion,
|
||||
"SetAtlas",
|
||||
(atlas.to_string(), t.attr_bool("useAtlasSize")),
|
||||
dbg,
|
||||
);
|
||||
}
|
||||
if let Some(mode) = t.attr("alphaMode") {
|
||||
this.call_region(®ion, "SetBlendMode", mode.to_string(), dbg);
|
||||
}
|
||||
@@ -338,28 +334,11 @@ impl Loader<'_> {
|
||||
);
|
||||
} else if let Some(c) = children_named(tt, "Color").next().map(color_of) {
|
||||
self.call(wrapper, "SetThumbTexture", (c[0], c[1], c[2], c[3]), dbg);
|
||||
} else if tt.attr("atlas").is_some() {
|
||||
// `atlas=` — the Era dialect (0950), same posture as the Button state textures
|
||||
// above: create the slot empty, resolve via SetAtlas below.
|
||||
self.call(
|
||||
wrapper,
|
||||
"SetThumbTexture",
|
||||
(String::new(), layer.clone()),
|
||||
dbg,
|
||||
);
|
||||
}
|
||||
// alphaMode / <Size> / <Anchors> / <TexCoords> apply to the thumb region the setter just
|
||||
// created — fetch it back through the getter and use the region methods (same shape as a
|
||||
// Button's state textures).
|
||||
if let Ok(region) = wrapper.call_method::<Table>("GetThumbTexture", ()) {
|
||||
if let Some(atlas) = tt.attr("atlas") {
|
||||
self.call_region(
|
||||
®ion,
|
||||
"SetAtlas",
|
||||
(atlas.to_string(), tt.attr_bool("useAtlasSize")),
|
||||
dbg,
|
||||
);
|
||||
}
|
||||
if let Some(mode) = tt.attr("alphaMode") {
|
||||
self.call_region(®ion, "SetBlendMode", mode.to_string(), dbg);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user