1use std::convert::{TryFrom, TryInto};
2use std::io;
3
4use swf_types as ast;
5
6use crate::basic_data_types::{emit_color_transform_with_alpha, emit_matrix};
7use crate::display::{emit_blend_mode, emit_filter_list};
8use crate::primitives::{emit_le_u16, emit_u8};
9use crate::sound::emit_sound_info;
10
11#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub(crate) enum ButtonVersion {
13 Button1,
14 Button2,
15}
16
17pub(crate) fn get_min_button_version(value: &ast::tags::DefineButton) -> ButtonVersion {
18 if value.track_as_menu {
19 return ButtonVersion::Button2;
20 }
21 for record in &value.records {
22 let is_default_color_transform = record.color_transform == ast::ColorTransformWithAlpha::default();
23
24 if !is_default_color_transform || !record.filters.is_empty() || record.blend_mode != ast::BlendMode::Normal {
25 return ButtonVersion::Button2;
26 }
27 }
28
29 if value.actions.len() != 1 {
30 return ButtonVersion::Button2;
31 }
32 let action = &value.actions[0];
33 if action.conditions.is_some() {
34 return ButtonVersion::Button2;
35 }
36 ButtonVersion::Button1
37}
38
39pub(crate) fn emit_button_record_string<W: io::Write>(
40 writer: &mut W,
41 value: &[ast::ButtonRecord],
42 version: ButtonVersion,
43) -> io::Result<()> {
44 for record in value {
45 emit_button_record(writer, record, version)?;
46 }
47 emit_u8(writer, 0)
48}
49
50pub(crate) fn emit_button_record<W: io::Write>(
51 writer: &mut W,
52 value: &ast::ButtonRecord,
53 version: ButtonVersion,
54) -> io::Result<()> {
55 let has_filters = !value.filters.is_empty();
56 let has_blend_mode = value.blend_mode != ast::BlendMode::Normal;
57
58 #[allow(clippy::identity_op)]
59 let flags: u8 = 0
60 | (if value.state_up { 1 << 0 } else { 0 })
61 | (if value.state_over { 1 << 1 } else { 0 })
62 | (if value.state_down { 1 << 2 } else { 0 })
63 | (if value.state_hit_test { 1 << 3 } else { 0 })
64 | (if has_filters { 1 << 4 } else { 0 })
65 | (if has_blend_mode { 1 << 5 } else { 0 });
66 emit_u8(writer, flags)?;
68
69 emit_le_u16(writer, value.character_id)?;
70 emit_le_u16(writer, value.depth)?;
71 emit_matrix(writer, &value.matrix)?;
72 if version >= ButtonVersion::Button2 {
73 emit_color_transform_with_alpha(writer, &value.color_transform)?;
74 if has_filters {
75 emit_filter_list(writer, &value.filters)?;
76 }
77 if has_blend_mode {
78 emit_blend_mode(writer, value.blend_mode)?;
79 }
80 }
81 Ok(())
82}
83
84pub(crate) fn emit_button2_cond_action_string<W: io::Write>(
85 writer: &mut W,
86 value: &[ast::ButtonCondAction],
87) -> io::Result<()> {
88 debug_assert!(!value.is_empty());
89 for (index, action) in value.iter().enumerate() {
90 let mut action_writer = Vec::new();
91 emit_button2_cond_action(&mut action_writer, action)?;
92 if index == value.len() - 1 {
93 emit_le_u16(writer, action_writer.len().try_into().unwrap())?;
95 } else {
96 emit_le_u16(writer, 0)?;
98 }
99 writer.write_all(&action_writer)?;
100 }
101 Ok(())
102}
103
104pub(crate) fn emit_button2_cond_action<W: io::Write>(writer: &mut W, value: &ast::ButtonCondAction) -> io::Result<()> {
105 emit_button_cond(writer, &value.conditions.unwrap())?;
106 writer.write_all(&value.actions)
107}
108
109pub(crate) fn emit_button_cond<W: io::Write>(writer: &mut W, value: &ast::ButtonCond) -> io::Result<()> {
110 let key_code: u16 = match value.key_press {
111 Some(key_code) => u16::try_from(key_code).unwrap() & 0x7f,
112 None => 0,
113 };
114 #[allow(clippy::identity_op)]
115 let flags: u16 = 0
116 | (if value.idle_to_over_up { 1 << 0 } else { 0 })
117 | (if value.over_up_to_idle { 1 << 1 } else { 0 })
118 | (if value.over_up_to_over_down { 1 << 2 } else { 0 })
119 | (if value.over_down_to_over_up { 1 << 3 } else { 0 })
120 | (if value.over_down_to_out_down { 1 << 4 } else { 0 })
121 | (if value.out_down_to_over_down { 1 << 5 } else { 0 })
122 | (if value.out_down_to_idle { 1 << 6 } else { 0 })
123 | (if value.idle_to_over_down { 1 << 7 } else { 0 })
124 | (if value.over_down_to_idle { 1 << 8 } else { 0 })
125 | (key_code << 9);
126 emit_le_u16(writer, flags)
127}
128
129pub(crate) fn emit_button_sound<W: io::Write>(writer: &mut W, value: &Option<ast::ButtonSound>) -> io::Result<()> {
130 match value {
131 None => emit_le_u16(writer, 0)?,
132 Some(value) => {
133 assert_ne!(value.sound_id, 0);
134 emit_le_u16(writer, value.sound_id)?;
135 emit_sound_info(writer, &value.sound_info)?;
136 }
137 }
138 Ok(())
139}