A MessageFrame's link is text; only chat lines take link buttons (#1149)
- A MessageFrame's link is text; only chat lines take link buttons - set_spans' doc says only a ScrollingMessageFrame's spans take buttons Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Sam <samuv.eth@gmail.com>
This commit is contained in:
@@ -480,6 +480,11 @@ mod caret_tests {
|
||||
fn app_with(lua: &str) -> App {
|
||||
let script = UiScript::new().unwrap();
|
||||
script.run(lua).unwrap();
|
||||
app_on(script)
|
||||
}
|
||||
|
||||
/// The whole UI pass on a 1024×768 window (`s = 1`) over `script`.
|
||||
pub(super) fn app_on(script: UiScript) -> App {
|
||||
let mut app = App::new();
|
||||
app.insert_non_send_resource(script);
|
||||
app.insert_resource(UiFontAtlas::for_test(1.0).expect("the client faces open"));
|
||||
@@ -625,3 +630,56 @@ mod caret_tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A message line's links through the whole UI pass, on the stock `UIErrorsFrame`.
|
||||
#[cfg(test)]
|
||||
mod link_span_tests {
|
||||
use benilla_ui::script::UiScript;
|
||||
|
||||
use super::caret_tests::app_on;
|
||||
use crate::ui_script::test_ui::load_ui;
|
||||
|
||||
const LINE: &str = "|cff1eff00|Hitem:7073:0:0:0|h[Broken Fang]|h|r";
|
||||
|
||||
/// Stock `UIErrorsFrame` is a `<MessageFrame>` (`UIErrorsFrame.xml:4`), whose update
|
||||
/// (`0x786200`) never takes a link button (`0x7a3880`), so its link line takes no mouse; a
|
||||
/// ScrollingMessageFrame's same line does (`0x788ce7`).
|
||||
#[test]
|
||||
fn a_link_in_the_stock_errors_frame_takes_no_mouse() {
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let script = UiScript::new().unwrap();
|
||||
for file in [
|
||||
"Interface\\FrameXML\\GlobalStrings.lua",
|
||||
"Interface\\FrameXML\\Fonts.xml",
|
||||
"Interface\\FrameXML\\UIParent.xml",
|
||||
"Interface\\FrameXML\\UIErrorsFrame.xml",
|
||||
] {
|
||||
load_ui(&script, file);
|
||||
}
|
||||
script
|
||||
.run(&format!(
|
||||
r#"
|
||||
UIErrorsFrame:AddMessage("{LINE}", 1.0, 0.1, 0.1, 1.0)
|
||||
CF = CreateFrame("ScrollingMessageFrame", "CF", UIParent)
|
||||
CF:SetPoint("BOTTOMLEFT", 32, 100); CF:SetWidth(430); CF:SetHeight(120)
|
||||
CF:SetFontObject(ChatFontNormal)
|
||||
CF:AddMessage("{LINE}")
|
||||
"#
|
||||
))
|
||||
.unwrap();
|
||||
let app = app_on(script);
|
||||
let s = app.world().non_send_resource::<UiScript>();
|
||||
assert_eq!(
|
||||
s.eval::<i64>("return CF:GetNumChildren()").unwrap(),
|
||||
1,
|
||||
"the chat line's link has its button"
|
||||
);
|
||||
assert_eq!(
|
||||
s.eval::<i64>("return UIErrorsFrame:GetNumChildren()")
|
||||
.unwrap(),
|
||||
0,
|
||||
"the error line's link is text"
|
||||
);
|
||||
assert!(s.errors().is_empty(), "{:?}", s.errors());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,9 +78,9 @@ fn fire(lua: &Lua, owner: FrameHandle, script: &str, args: &[&str]) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace the spans on screen, `(text frame, y-up rect, link, text)`: each text frame's spans take
|
||||
/// its pooled buttons in order, a new one built when the pool runs out, and the buttons left over,
|
||||
/// or of a text frame with no span now, hide.
|
||||
/// Replace the spans on screen, `(text frame, y-up rect, link, text)`: each ScrollingMessageFrame's
|
||||
/// spans take its pooled buttons in order, a new one built when the pool runs out, and the buttons
|
||||
/// left over, or of a text frame with no span now, hide. A MessageFrame's spans stay text.
|
||||
pub(super) fn set_spans(lua: &Lua, spans: Vec<(FrameHandle, Rect, String, String)>) {
|
||||
// One span: its rect, link and text.
|
||||
type Span = (Rect, String, String);
|
||||
@@ -100,7 +100,12 @@ pub(super) fn set_spans(lua: &Lua, spans: Vec<(FrameHandle, Rect, String, String
|
||||
.link_buttons
|
||||
.retain(|owner, _| model.arena.frame(*owner).is_some());
|
||||
for (owner, list) in &by_owner {
|
||||
if model.arena.frame(*owner).is_none() {
|
||||
// Only the SMF (`0x788ce7`) and SimpleHTML (`0x78b052`) take one; ours draws no links.
|
||||
if !model
|
||||
.arena
|
||||
.frame(*owner)
|
||||
.is_some_and(|f| matches!(f.kind_state, KindState::ScrollingMessage(_)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (i, (rect, link, text)) in list.iter().enumerate() {
|
||||
|
||||
@@ -29,14 +29,14 @@ fn chat() -> UiScript {
|
||||
)
|
||||
.unwrap();
|
||||
s.resolve();
|
||||
set_link(&mut s);
|
||||
set_link(&mut s, "CF");
|
||||
s
|
||||
}
|
||||
|
||||
fn set_link(s: &mut UiScript) {
|
||||
let cf = s.model_ref().arena.lookup("CF").expect("CF");
|
||||
fn set_link(s: &mut UiScript, owner: &str) {
|
||||
let owner = s.model_ref().arena.lookup(owner).expect("owner");
|
||||
s.set_link_spans(vec![(
|
||||
cf,
|
||||
owner,
|
||||
Rect::new(120.0, 110.0, 134.0, 160.0),
|
||||
LINK.to_string(),
|
||||
MARKUP.to_string(),
|
||||
@@ -140,3 +140,25 @@ fn a_hittable_body_title_drags_but_its_link_still_clicks() {
|
||||
assert!(s.eval::<bool>("return CF:IsUserPlaced()").unwrap());
|
||||
assert!(s.errors().is_empty(), "{:?}", s.errors());
|
||||
}
|
||||
|
||||
/// The take `0x7a3880` is called from the ScrollingMessageFrame and SimpleHTML updates alone; the
|
||||
/// MessageFrame's update (`0x786200`) reaches neither, so a span on one builds no button and the
|
||||
/// pointer over it passes through.
|
||||
#[test]
|
||||
fn a_message_frame_line_gets_no_link_button() {
|
||||
let mut s = script();
|
||||
s.set_screen_size(800.0, 600.0);
|
||||
s.run(
|
||||
r#"
|
||||
EF = CreateFrame("MessageFrame", "EF")
|
||||
EF:SetPoint("BOTTOMLEFT", 100, 100); EF:SetWidth(430); EF:SetHeight(120)
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
s.resolve();
|
||||
set_link(&mut s, "EF");
|
||||
assert_eq!(s.eval::<i64>("return EF:GetNumChildren()").unwrap(), 0);
|
||||
s.mouse_move(130.0, 127.0);
|
||||
assert!(s.eval::<bool>("return GetMouseFocus() == nil").unwrap());
|
||||
assert!(s.errors().is_empty(), "{:?}", s.errors());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user