swf_emitter/
button.rs

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  // Skip bits [6, 7]
67  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      // !is_last
94      emit_le_u16(writer, action_writer.len().try_into().unwrap())?;
95    } else {
96      // is_last
97      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}