swf: Use bitflags for EditText

This commit is contained in:
Mike Welsh 2022-09-02 19:54:38 -07:00
parent 53ed748a54
commit b1404edfdc
6 changed files with 460 additions and 216 deletions

View File

@ -210,13 +210,13 @@ impl<'gc> EditText<'gc> {
swf_movie: Arc<SwfMovie>, swf_movie: Arc<SwfMovie>,
swf_tag: swf::EditText, swf_tag: swf::EditText,
) -> Self { ) -> Self {
let is_multiline = swf_tag.is_multiline; let is_multiline = swf_tag.is_multiline();
let is_word_wrap = swf_tag.is_word_wrap; let is_word_wrap = swf_tag.is_word_wrap();
let is_selectable = swf_tag.is_selectable; let is_selectable = swf_tag.is_selectable();
let is_password = swf_tag.is_password; let is_password = swf_tag.is_password();
let is_editable = !swf_tag.is_read_only; let is_editable = !swf_tag.is_read_only();
let is_html = swf_tag.is_html; let is_html = swf_tag.is_html();
let text = swf_tag.initial_text.unwrap_or_default(); let text = swf_tag.initial_text().unwrap_or_default();
let default_format = TextFormat::from_swf_tag(swf_tag.clone(), swf_movie.clone(), context); let default_format = TextFormat::from_swf_tag(swf_tag.clone(), swf_movie.clone(), context);
let encoding = swf_movie.encoding(); let encoding = swf_movie.encoding();
@ -231,37 +231,37 @@ impl<'gc> EditText<'gc> {
text_spans.hide_text(); text_spans.hide_text();
} }
let autosize = if swf_tag.is_auto_size { let autosize = if swf_tag.is_auto_size() {
AutoSizeMode::Left AutoSizeMode::Left
} else { } else {
AutoSizeMode::None AutoSizeMode::None
}; };
let bounds: BoundingBox = (&swf_tag.bounds).into(); let bounds: BoundingBox = swf_tag.bounds().into();
let (layout, intrinsic_bounds) = LayoutBox::lower_from_text_spans( let (layout, intrinsic_bounds) = LayoutBox::lower_from_text_spans(
&text_spans, &text_spans,
context, context,
swf_movie.clone(), swf_movie.clone(),
bounds.width() - Twips::from_pixels(Self::INTERNAL_PADDING * 2.0), bounds.width() - Twips::from_pixels(Self::INTERNAL_PADDING * 2.0),
swf_tag.is_word_wrap, swf_tag.is_word_wrap(),
swf_tag.is_device_font, !swf_tag.use_outlines(),
); );
let line_data = get_line_data(&layout); let line_data = get_line_data(&layout);
let has_background = swf_tag.has_border; let has_background = swf_tag.has_border();
let background_color = 0xFFFFFF; // Default is white let background_color = 0xFFFFFF; // Default is white
let has_border = swf_tag.has_border; let has_border = swf_tag.has_border();
let border_color = 0; // Default is black let border_color = 0; // Default is black
let is_device_font = swf_tag.is_device_font; let is_device_font = !swf_tag.use_outlines();
let mut base = InteractiveObjectBase::default(); let mut base = InteractiveObjectBase::default();
base.base.matrix_mut().tx = bounds.x_min; base.base.matrix_mut().tx = bounds.x_min;
base.base.matrix_mut().ty = bounds.y_min; base.base.matrix_mut().ty = bounds.y_min;
let variable = if !swf_tag.variable_name.is_empty() { let variable = if !swf_tag.variable_name().is_empty() {
Some(swf_tag.variable_name) Some(swf_tag.variable_name())
} else { } else {
None None
}; };
@ -276,32 +276,32 @@ impl<'gc> EditText<'gc> {
EditTextStatic { EditTextStatic {
swf: swf_movie, swf: swf_movie,
text: EditTextStaticData { text: EditTextStaticData {
id: swf_tag.id, id: swf_tag.id(),
bounds: swf_tag.bounds, bounds: swf_tag.bounds().clone(),
font_id: swf_tag.font_id, font_id: swf_tag.font_id(),
font_class_name: swf_tag font_class_name: swf_tag
.font_class_name .font_class()
.map(|s| s.to_string_lossy(encoding)), .map(|s| s.to_string_lossy(encoding)),
height: swf_tag.height, height: swf_tag.height(),
color: swf_tag.color.clone(), color: swf_tag.color().cloned(),
max_length: swf_tag.max_length, max_length: swf_tag.max_length(),
layout: swf_tag.layout.clone(), layout: swf_tag.layout().cloned(),
variable_name: WString::from_utf8_owned( variable_name: WString::from_utf8_owned(
swf_tag.variable_name.to_string_lossy(encoding), swf_tag.variable_name().to_string_lossy(encoding),
), ),
initial_text: swf_tag initial_text: swf_tag
.initial_text .initial_text()
.map(|s| WString::from_utf8_owned(s.to_string_lossy(encoding))), .map(|s| WString::from_utf8_owned(s.to_string_lossy(encoding))),
is_word_wrap: swf_tag.is_word_wrap, is_word_wrap: swf_tag.is_word_wrap(),
is_multiline: swf_tag.is_multiline, is_multiline: swf_tag.is_multiline(),
is_password: swf_tag.is_password, is_password: swf_tag.is_password(),
is_read_only: swf_tag.is_read_only, is_read_only: swf_tag.is_read_only(),
is_auto_size: swf_tag.is_auto_size, is_auto_size: swf_tag.is_auto_size(),
is_selectable: swf_tag.is_selectable, is_selectable: swf_tag.is_selectable(),
has_border: swf_tag.has_border, has_border: swf_tag.has_border(),
was_static: swf_tag.was_static, was_static: swf_tag.was_static(),
is_html: swf_tag.is_html, is_html: swf_tag.is_html(),
is_device_font: swf_tag.is_device_font, is_device_font: !swf_tag.use_outlines(),
}, },
}, },
), ),
@ -334,7 +334,7 @@ impl<'gc> EditText<'gc> {
}, },
)); ));
if swf_tag.is_auto_size { if swf_tag.is_auto_size() {
et.relayout(context); et.relayout(context);
} else { } else {
et.redraw_border(context.gc_context); et.redraw_border(context.gc_context);
@ -352,45 +352,16 @@ impl<'gc> EditText<'gc> {
width: f64, width: f64,
height: f64, height: f64,
) -> Self { ) -> Self {
let swf_tag = swf::EditText { let swf_tag = swf::EditText::new()
id: 0, //TODO: Dynamic text fields don't have a character ID? .with_font_id(0, Twips::from_pixels(12.0))
bounds: swf::Rectangle { .with_color(Some(Color::BLACK))
.with_bounds(swf::Rectangle {
x_min: Twips::from_pixels(0.0), x_min: Twips::from_pixels(0.0),
x_max: Twips::from_pixels(width), x_max: Twips::from_pixels(width),
y_min: Twips::from_pixels(0.0), y_min: Twips::from_pixels(0.0),
y_max: Twips::from_pixels(height), y_max: Twips::from_pixels(height),
}, })
font_id: None, .with_layout(Default::default());
font_class_name: None,
height: Some(Twips::from_pixels(12.0)),
color: Some(swf::Color {
r: 0,
g: 0,
b: 0,
a: 0xFF,
}),
max_length: Some(width as u16),
layout: Some(swf::TextLayout {
align: swf::TextAlign::Left,
left_margin: Twips::from_pixels(0.0),
right_margin: Twips::from_pixels(0.0),
indent: Twips::from_pixels(0.0),
leading: Twips::from_pixels(0.0),
}),
variable_name: "".into(), //TODO: should be null
initial_text: None,
is_word_wrap: false,
is_multiline: false,
is_password: false,
is_read_only: true,
is_auto_size: false,
is_selectable: true,
has_border: false,
was_static: false,
is_html: false,
is_device_font: false,
};
let text_field = Self::from_swf_tag(context, swf_movie, swf_tag); let text_field = Self::from_swf_tag(context, swf_movie, swf_tag);
// Set position. // Set position.

View File

@ -142,26 +142,26 @@ impl TextFormat {
) -> Self { ) -> Self {
let encoding = swf_movie.encoding(); let encoding = swf_movie.encoding();
let movie_library = context.library.library_for_movie_mut(swf_movie); let movie_library = context.library.library_for_movie_mut(swf_movie);
let font = et.font_id.and_then(|fid| movie_library.get_font(fid)); let font = et.font_id().and_then(|fid| movie_library.get_font(fid));
let font_class = et let font_class = et
.font_class_name .font_class()
.map(|s| WString::from_utf8(&s.to_string_lossy(encoding))) .map(|s| WString::from_utf8(&s.to_string_lossy(encoding)))
.or_else(|| font.map(|font| WString::from_utf8(font.descriptor().class()))) .or_else(|| font.map(|font| WString::from_utf8(font.descriptor().class())))
.unwrap_or_else(|| WString::from_utf8("Times New Roman")); .unwrap_or_else(|| WString::from_utf8("Times New Roman"));
let align = et.layout.as_ref().map(|l| l.align); let align = et.layout().map(|l| l.align);
let left_margin = et.layout.as_ref().map(|l| l.left_margin.to_pixels()); let left_margin = et.layout().map(|l| l.left_margin.to_pixels());
let right_margin = et.layout.as_ref().map(|l| l.right_margin.to_pixels()); let right_margin = et.layout().map(|l| l.right_margin.to_pixels());
let indent = et.layout.as_ref().map(|l| l.indent.to_pixels()); let indent = et.layout().map(|l| l.indent.to_pixels());
let leading = et.layout.map(|l| l.leading.to_pixels()); let leading = et.layout().map(|l| l.leading.to_pixels());
// TODO: Text fields that don't specify a font are assumed to be 12px // TODO: Text fields that don't specify a font are assumed to be 12px
// Times New Roman non-bold, non-italic. This will need to be revised // Times New Roman non-bold, non-italic. This will need to be revised
// when we start supporting device fonts. // when we start supporting device fonts.
Self { Self {
font: Some(font_class), font: Some(font_class),
size: et.height.map(|h| h.to_pixels()), size: et.height().map(|h| h.to_pixels()),
color: et color: et
.color .color()
.map(|color| swf::Color::from_rgb(color.to_rgb(), 0)), .map(|color| swf::Color::from_rgb(color.to_rgb(), 0)),
align, align,
bold: Some(font.map(|font| font.descriptor().bold()).unwrap_or(false)), bold: Some(font.map(|font| font.descriptor().bold()).unwrap_or(false)),

View File

@ -2348,72 +2348,68 @@ impl<'a> Reader<'a> {
pub fn read_define_edit_text(&mut self) -> Result<EditText<'a>> { pub fn read_define_edit_text(&mut self) -> Result<EditText<'a>> {
let id = self.read_character_id()?; let id = self.read_character_id()?;
let bounds = self.read_rectangle()?; let bounds = self.read_rectangle()?;
let flags = self.read_u8()?; let flags = EditTextFlag::from_bits_truncate(self.read_u16()?);
let flags2 = self.read_u8()?; let font_id = if flags.contains(EditTextFlag::HAS_FONT) {
let font_id = if flags & 0b1 != 0 { self.read_character_id()?
Some(self.read_character_id()?)
} else { } else {
None Default::default()
}; };
let font_class_name = if flags2 & 0b10000000 != 0 { let font_class = if flags.contains(EditTextFlag::HAS_FONT_CLASS) {
Some(self.read_str()?) self.read_str()?
} else { } else {
None Default::default()
}; };
let height = if flags & 0b1 != 0 { let height = if flags.contains(EditTextFlag::HAS_FONT) {
Some(Twips::new(self.read_u16()?)) Twips::new(self.read_u16()?)
} else { } else {
None Twips::ZERO
}; };
let color = if flags & 0b100 != 0 { let color = if flags.contains(EditTextFlag::HAS_TEXT_COLOR) {
Some(self.read_rgba()?) self.read_rgba()?
} else { } else {
None Color::BLACK
}; };
let max_length = if flags & 0b10 != 0 { let max_length = if flags.contains(EditTextFlag::HAS_MAX_LENGTH) {
Some(self.read_u16()?) self.read_u16()?
} else { } else {
None 0
}; };
let layout = if flags2 & 0b100000 != 0 { let layout = if flags.contains(EditTextFlag::HAS_LAYOUT) {
Some(TextLayout { TextLayout {
align: TextAlign::from_u8(self.read_u8()?) align: TextAlign::from_u8(self.read_u8()?)
.ok_or_else(|| Error::invalid_data("Invalid edit text alignment"))?, .ok_or_else(|| Error::invalid_data("Invalid edit text alignment"))?,
left_margin: Twips::new(self.read_u16()?), left_margin: Twips::new(self.read_u16()?),
right_margin: Twips::new(self.read_u16()?), right_margin: Twips::new(self.read_u16()?),
indent: Twips::new(self.read_u16()?), indent: Twips::new(self.read_u16()?),
leading: Twips::new(self.read_i16()?), leading: Twips::new(self.read_i16()?),
}) }
} else { } else {
None TextLayout {
align: TextAlign::Left,
left_margin: Twips::ZERO,
right_margin: Twips::ZERO,
indent: Twips::ZERO,
leading: Twips::ZERO,
}
}; };
let variable_name = self.read_str()?; let variable_name = self.read_str()?;
let initial_text = if flags & 0b10000000 != 0 { let initial_text = if flags.contains(EditTextFlag::HAS_TEXT) {
Some(self.read_str()?) self.read_str()?
} else { } else {
None Default::default()
}; };
Ok(EditText { Ok(EditText {
id, id,
bounds, bounds,
font_id, font_id,
font_class_name, font_class,
height, height,
color, color,
max_length, max_length,
layout, layout,
variable_name, variable_name,
initial_text, initial_text,
is_word_wrap: flags & 0b1000000 != 0, flags,
is_multiline: flags & 0b100000 != 0,
is_password: flags & 0b10000 != 0,
is_read_only: flags & 0b1000 != 0,
is_auto_size: flags2 & 0b1000000 != 0,
is_selectable: flags2 & 0b10000 == 0,
has_border: flags2 & 0b1000 != 0,
was_static: flags2 & 0b100 != 0,
is_html: flags2 & 0b10 != 0,
is_device_font: flags2 & 0b1 == 0,
}) })
} }

View File

@ -359,44 +359,40 @@ pub fn tag_tests() -> Vec<TagTestData> {
), ),
( (
4, 4,
Tag::DefineEditText(Box::new(EditText { Tag::DefineEditText(Box::new(
id: 2, EditText::new()
bounds: Rectangle { .with_id(2)
x_min: Twips::from_pixels(-2.0), .with_font_id(1, Twips::from_pixels(18.0))
x_max: Twips::from_pixels(77.9), .with_bounds(Rectangle {
y_min: Twips::from_pixels(-2.0), x_min: Twips::from_pixels(-2.0),
y_max: Twips::from_pixels(23.9), x_max: Twips::from_pixels(77.9),
}, y_min: Twips::from_pixels(-2.0),
font_id: Some(1), y_max: Twips::from_pixels(23.9),
font_class_name: None, })
height: Some(Twips::from_pixels(18.0)), .with_color(Some(Color {
color: Some(Color { r: 0,
r: 0, g: 255,
g: 255, b: 0,
b: 0, a: 255,
a: 255, }))
}), .with_layout(Some(TextLayout {
max_length: None, align: TextAlign::Justify,
layout: Some(TextLayout { left_margin: Twips::from_pixels(3.0),
align: TextAlign::Justify, right_margin: Twips::from_pixels(4.0),
left_margin: Twips::from_pixels(3.0), indent: Twips::from_pixels(1.0),
right_margin: Twips::from_pixels(4.0), leading: Twips::from_pixels(2.0),
indent: Twips::from_pixels(1.0), }))
leading: Twips::from_pixels(2.0), .with_variable_name(
}), SwfStr::from_str_with_encoding("foo", WINDOWS_1252).unwrap(),
variable_name: SwfStr::from_str_with_encoding("foo", WINDOWS_1252).unwrap(), )
initial_text: Some(SwfStr::from_str_with_encoding("-_-", WINDOWS_1252).unwrap()), .with_initial_text(Some(
is_word_wrap: false, SwfStr::from_str_with_encoding("-_-", WINDOWS_1252).unwrap(),
is_multiline: true, ))
is_password: false, .with_is_read_only(true)
is_read_only: true, .with_has_border(true)
is_auto_size: false, .with_is_multiline(true)
is_selectable: true, .with_use_outlines(false),
has_border: true, )),
was_static: false,
is_html: false,
is_device_font: true,
})),
read_tag_bytes_from_file("tests/swfs/DefineEditText-MX.swf", TagCode::DefineEditText), read_tag_bytes_from_file("tests/swfs/DefineEditText-MX.swf", TagCode::DefineEditText),
), ),
( (

View File

@ -1337,29 +1337,340 @@ pub struct GlyphEntry {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct EditText<'a> { pub struct EditText<'a> {
pub id: CharacterId, pub(crate) id: CharacterId,
pub bounds: Rectangle, pub(crate) bounds: Rectangle,
pub font_id: Option<CharacterId>, // TODO(Herschel): Combine with height pub(crate) font_id: CharacterId,
pub font_class_name: Option<&'a SwfStr>, pub(crate) font_class: &'a SwfStr,
pub height: Option<Twips>, pub(crate) height: Twips,
pub color: Option<Color>, pub(crate) color: Color,
pub max_length: Option<u16>, pub(crate) max_length: u16,
pub layout: Option<TextLayout>, pub(crate) layout: TextLayout,
pub variable_name: &'a SwfStr, pub(crate) variable_name: &'a SwfStr,
pub initial_text: Option<&'a SwfStr>, pub(crate) initial_text: &'a SwfStr,
pub is_word_wrap: bool, pub(crate) flags: EditTextFlag,
pub is_multiline: bool,
pub is_password: bool,
pub is_read_only: bool,
pub is_auto_size: bool,
pub is_selectable: bool,
pub has_border: bool,
pub was_static: bool,
pub is_html: bool,
pub is_device_font: bool,
} }
#[derive(Clone, Debug, Eq, PartialEq)] impl<'a> EditText<'a> {
#[inline]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn bounds(&self) -> &Rectangle {
&self.bounds
}
#[inline]
pub fn with_bounds(mut self, bounds: Rectangle) -> Self {
self.bounds = bounds;
self
}
#[inline]
pub fn id(&self) -> CharacterId {
self.id
}
#[inline]
pub fn with_id(mut self, id: CharacterId) -> Self {
self.id = id;
self
}
#[inline]
pub fn font_id(&self) -> Option<CharacterId> {
self.flags
.contains(EditTextFlag::HAS_FONT)
.then_some(self.font_id)
}
// The height of the font in twips.
#[inline]
pub fn height(&self) -> Option<Twips> {
self.flags
.contains(EditTextFlag::HAS_FONT)
.then_some(self.height)
}
#[inline]
pub fn with_default_font(mut self) -> Self {
self.flags -= EditTextFlag::HAS_FONT;
self
}
#[inline]
pub fn with_font_id(mut self, font_id: CharacterId, height: Twips) -> Self {
self.flags |= EditTextFlag::HAS_FONT;
self.font_id = font_id;
self.height = height;
self
}
#[inline]
pub fn font_class(&self) -> Option<&'a SwfStr> {
self.flags
.contains(EditTextFlag::HAS_FONT_CLASS)
.then_some(self.font_class)
}
#[inline]
pub fn with_font_class(mut self, font_class_name: Option<&'a SwfStr>) -> Self {
if let Some(font_class_name) = font_class_name {
self.flags |= EditTextFlag::HAS_FONT_CLASS;
self.font_class = font_class_name;
} else {
self.flags -= EditTextFlag::HAS_FONT_CLASS;
}
self
}
#[inline]
pub fn color(&self) -> Option<&Color> {
self.flags
.contains(EditTextFlag::HAS_TEXT_COLOR)
.then_some(&self.color)
}
#[inline]
pub fn with_color(mut self, color: Option<Color>) -> Self {
if let Some(color) = color {
self.flags |= EditTextFlag::HAS_TEXT_COLOR;
self.color = color;
} else {
self.flags -= EditTextFlag::HAS_TEXT_COLOR;
}
self
}
#[inline]
pub fn max_length(&self) -> Option<u16> {
self.flags
.contains(EditTextFlag::HAS_MAX_LENGTH)
.then_some(self.max_length)
}
#[inline]
pub fn with_max_length(mut self, max_length: Option<u16>) -> Self {
if let Some(max_length) = max_length {
self.flags |= EditTextFlag::HAS_MAX_LENGTH;
self.max_length = max_length;
} else {
self.flags -= EditTextFlag::HAS_MAX_LENGTH;
}
self
}
#[inline]
pub fn layout(&self) -> Option<&TextLayout> {
self.flags
.contains(EditTextFlag::HAS_LAYOUT)
.then_some(&self.layout)
}
#[inline]
pub fn with_layout(mut self, layout: Option<TextLayout>) -> Self {
if let Some(layout) = layout {
self.flags |= EditTextFlag::HAS_LAYOUT;
self.layout = layout;
} else {
self.flags -= EditTextFlag::HAS_LAYOUT;
}
self
}
#[inline]
pub fn variable_name(&self) -> &'a SwfStr {
self.variable_name
}
#[inline]
pub fn with_variable_name(mut self, variable_name: &'a SwfStr) -> Self {
self.variable_name = variable_name;
self
}
#[inline]
pub fn initial_text(&self) -> Option<&'a SwfStr> {
self.flags
.contains(EditTextFlag::HAS_TEXT)
.then_some(self.initial_text)
}
#[inline]
pub fn with_initial_text(mut self, initial_text: Option<&'a SwfStr>) -> Self {
if let Some(initial_text) = initial_text {
self.flags |= EditTextFlag::HAS_TEXT;
self.initial_text = initial_text;
} else {
self.flags -= EditTextFlag::HAS_TEXT;
}
self
}
#[inline]
pub fn flags(&self) -> EditTextFlag {
self.flags
}
#[inline]
pub fn is_auto_size(&self) -> bool {
self.flags.contains(EditTextFlag::AUTO_SIZE)
}
#[inline]
pub fn with_is_auto_size(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::AUTO_SIZE, value);
self
}
#[inline]
pub fn use_outlines(&self) -> bool {
self.flags.contains(EditTextFlag::USE_OUTLINES)
}
#[inline]
pub fn with_use_outlines(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::USE_OUTLINES, value);
self
}
#[inline]
pub fn has_border(&self) -> bool {
self.flags.contains(EditTextFlag::BORDER)
}
#[inline]
pub fn with_has_border(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::BORDER, value);
self
}
#[inline]
pub fn is_html(&self) -> bool {
self.flags.contains(EditTextFlag::HTML)
}
#[inline]
pub fn with_is_html(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::HTML, value);
self
}
#[inline]
pub fn is_multiline(&self) -> bool {
self.flags.contains(EditTextFlag::MULTILINE)
}
#[inline]
pub fn with_is_multiline(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::MULTILINE, value);
self
}
#[inline]
pub fn is_password(&self) -> bool {
self.flags.contains(EditTextFlag::PASSWORD)
}
#[inline]
pub fn with_is_password(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::PASSWORD, value);
self
}
#[inline]
pub fn is_read_only(&self) -> bool {
self.flags.contains(EditTextFlag::READ_ONLY)
}
#[inline]
pub fn with_is_read_only(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::READ_ONLY, value);
self
}
#[inline]
pub fn is_selectable(&self) -> bool {
!self.flags.contains(EditTextFlag::NO_SELECT)
}
#[inline]
pub fn with_is_selectable(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::NO_SELECT, !value);
self
}
#[inline]
pub fn was_static(&self) -> bool {
self.flags.contains(EditTextFlag::WAS_STATIC)
}
#[inline]
pub fn with_was_static(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::WAS_STATIC, value);
self
}
#[inline]
pub fn is_word_wrap(&self) -> bool {
self.flags.contains(EditTextFlag::WORD_WRAP)
}
#[inline]
pub fn with_is_word_wrap(mut self, value: bool) -> Self {
self.flags.set(EditTextFlag::WORD_WRAP, value);
self
}
}
impl<'a> Default for EditText<'a> {
fn default() -> Self {
Self {
id: Default::default(),
bounds: Default::default(),
font_id: Default::default(),
font_class: Default::default(),
height: Twips::ZERO,
color: Color::BLACK,
max_length: 0,
layout: TextLayout {
align: TextAlign::Left,
left_margin: Twips::ZERO,
right_margin: Twips::ZERO,
indent: Twips::ZERO,
leading: Twips::ZERO,
},
variable_name: Default::default(),
initial_text: Default::default(),
flags: EditTextFlag::empty(),
}
}
}
bitflags! {
pub struct EditTextFlag: u16 {
const HAS_FONT = 1 << 0;
const HAS_MAX_LENGTH = 1 << 1;
const HAS_TEXT_COLOR = 1 << 2;
const READ_ONLY = 1 << 3;
const PASSWORD = 1 << 4;
const MULTILINE = 1 << 5;
const WORD_WRAP = 1 << 6;
const HAS_TEXT = 1 << 7;
const USE_OUTLINES = 1 << 8;
const HTML = 1 << 9;
const WAS_STATIC = 1 << 10;
const BORDER = 1 << 11;
const NO_SELECT = 1 << 12;
const HAS_LAYOUT = 1 << 13;
const AUTO_SIZE = 1 << 14;
const HAS_FONT_CLASS = 1 << 15;
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TextLayout { pub struct TextLayout {
pub align: TextAlign, pub align: TextAlign,
pub left_margin: Twips, pub left_margin: Twips,
@ -1368,8 +1679,9 @@ pub struct TextLayout {
pub leading: Twips, pub leading: Twips,
} }
#[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq)] #[derive(Clone, Copy, Debug, Default, Eq, FromPrimitive, PartialEq)]
pub enum TextAlign { pub enum TextAlign {
#[default]
Left = 0, Left = 0,
Right = 1, Right = 1,
Center = 2, Center = 2,

View File

@ -2262,63 +2262,31 @@ impl<W: Write> Writer<W> {
let mut writer = Writer::new(&mut buf, self.version); let mut writer = Writer::new(&mut buf, self.version);
writer.write_character_id(edit_text.id)?; writer.write_character_id(edit_text.id)?;
writer.write_rectangle(&edit_text.bounds)?; writer.write_rectangle(&edit_text.bounds)?;
let flags = if edit_text.initial_text.is_some() { writer.write_u16(edit_text.flags.bits() as u16)?;
0b10000000
} else {
0
} | if edit_text.is_word_wrap { 0b1000000 } else { 0 }
| if edit_text.is_multiline { 0b100000 } else { 0 }
| if edit_text.is_password { 0b10000 } else { 0 }
| if edit_text.is_read_only { 0b1000 } else { 0 }
| if edit_text.color.is_some() { 0b100 } else { 0 }
| if edit_text.max_length.is_some() {
0b10
} else {
0
}
| if edit_text.font_id.is_some() { 0b1 } else { 0 };
let flags2 = if edit_text.font_class_name.is_some() {
0b10000000
} else {
0
} | if edit_text.is_auto_size { 0b1000000 } else { 0 }
| if edit_text.layout.is_some() {
0b100000
} else {
0
}
| if !edit_text.is_selectable { 0b10000 } else { 0 }
| if edit_text.has_border { 0b1000 } else { 0 }
| if edit_text.was_static { 0b100 } else { 0 }
| if edit_text.is_html { 0b10 } else { 0 }
| if !edit_text.is_device_font { 0b1 } else { 0 };
writer.write_u8(flags)?; if let Some(font_id) = edit_text.font_id() {
writer.write_u8(flags2)?;
if let Some(font_id) = edit_text.font_id {
writer.write_character_id(font_id)?; writer.write_character_id(font_id)?;
} }
// TODO(Herschel): Check SWF version. // TODO(Herschel): Check SWF version.
if let Some(class) = edit_text.font_class_name { if let Some(class) = edit_text.font_class() {
writer.write_string(class)?; writer.write_string(class)?;
} }
// TODO(Herschel): Height only exists iff HasFontId, maybe for HasFontClass too? // TODO(Herschel): Height only exists iff HasFontId, maybe for HasFontClass too?
if let Some(height) = edit_text.height { if let Some(height) = edit_text.height() {
writer.write_u16(height.get() as u16)? writer.write_u16(height.get() as u16)?
} }
if let Some(ref color) = edit_text.color { if let Some(color) = edit_text.color() {
writer.write_rgba(color)? writer.write_rgba(color)?
} }
if let Some(len) = edit_text.max_length { if let Some(len) = edit_text.max_length() {
writer.write_u16(len)?; writer.write_u16(len)?;
} }
if let Some(ref layout) = edit_text.layout { if let Some(layout) = edit_text.layout() {
writer.write_u8(layout.align as u8)?; writer.write_u8(layout.align as u8)?;
writer.write_u16(layout.left_margin.get() as u16)?; // TODO: Handle overflow writer.write_u16(layout.left_margin.get() as u16)?; // TODO: Handle overflow
writer.write_u16(layout.right_margin.get() as u16)?; writer.write_u16(layout.right_margin.get() as u16)?;
@ -2327,7 +2295,8 @@ impl<W: Write> Writer<W> {
} }
writer.write_string(edit_text.variable_name)?; writer.write_string(edit_text.variable_name)?;
if let Some(text) = edit_text.initial_text {
if let Some(text) = edit_text.initial_text() {
writer.write_string(text)?; writer.write_string(text)?;
} }
} }