swf: Use bitflags for EditText
This commit is contained in:
parent
53ed748a54
commit
b1404edfdc
|
@ -210,13 +210,13 @@ impl<'gc> EditText<'gc> {
|
|||
swf_movie: Arc<SwfMovie>,
|
||||
swf_tag: swf::EditText,
|
||||
) -> Self {
|
||||
let is_multiline = swf_tag.is_multiline;
|
||||
let is_word_wrap = swf_tag.is_word_wrap;
|
||||
let is_selectable = swf_tag.is_selectable;
|
||||
let is_password = swf_tag.is_password;
|
||||
let is_editable = !swf_tag.is_read_only;
|
||||
let is_html = swf_tag.is_html;
|
||||
let text = swf_tag.initial_text.unwrap_or_default();
|
||||
let is_multiline = swf_tag.is_multiline();
|
||||
let is_word_wrap = swf_tag.is_word_wrap();
|
||||
let is_selectable = swf_tag.is_selectable();
|
||||
let is_password = swf_tag.is_password();
|
||||
let is_editable = !swf_tag.is_read_only();
|
||||
let is_html = swf_tag.is_html();
|
||||
let text = swf_tag.initial_text().unwrap_or_default();
|
||||
let default_format = TextFormat::from_swf_tag(swf_tag.clone(), swf_movie.clone(), context);
|
||||
let encoding = swf_movie.encoding();
|
||||
|
||||
|
@ -231,37 +231,37 @@ impl<'gc> EditText<'gc> {
|
|||
text_spans.hide_text();
|
||||
}
|
||||
|
||||
let autosize = if swf_tag.is_auto_size {
|
||||
let autosize = if swf_tag.is_auto_size() {
|
||||
AutoSizeMode::Left
|
||||
} else {
|
||||
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(
|
||||
&text_spans,
|
||||
context,
|
||||
swf_movie.clone(),
|
||||
bounds.width() - Twips::from_pixels(Self::INTERNAL_PADDING * 2.0),
|
||||
swf_tag.is_word_wrap,
|
||||
swf_tag.is_device_font,
|
||||
swf_tag.is_word_wrap(),
|
||||
!swf_tag.use_outlines(),
|
||||
);
|
||||
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 has_border = swf_tag.has_border;
|
||||
let has_border = swf_tag.has_border();
|
||||
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();
|
||||
|
||||
base.base.matrix_mut().tx = bounds.x_min;
|
||||
base.base.matrix_mut().ty = bounds.y_min;
|
||||
|
||||
let variable = if !swf_tag.variable_name.is_empty() {
|
||||
Some(swf_tag.variable_name)
|
||||
let variable = if !swf_tag.variable_name().is_empty() {
|
||||
Some(swf_tag.variable_name())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -276,32 +276,32 @@ impl<'gc> EditText<'gc> {
|
|||
EditTextStatic {
|
||||
swf: swf_movie,
|
||||
text: EditTextStaticData {
|
||||
id: swf_tag.id,
|
||||
bounds: swf_tag.bounds,
|
||||
font_id: swf_tag.font_id,
|
||||
id: swf_tag.id(),
|
||||
bounds: swf_tag.bounds().clone(),
|
||||
font_id: swf_tag.font_id(),
|
||||
font_class_name: swf_tag
|
||||
.font_class_name
|
||||
.font_class()
|
||||
.map(|s| s.to_string_lossy(encoding)),
|
||||
height: swf_tag.height,
|
||||
color: swf_tag.color.clone(),
|
||||
max_length: swf_tag.max_length,
|
||||
layout: swf_tag.layout.clone(),
|
||||
height: swf_tag.height(),
|
||||
color: swf_tag.color().cloned(),
|
||||
max_length: swf_tag.max_length(),
|
||||
layout: swf_tag.layout().cloned(),
|
||||
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
|
||||
.initial_text()
|
||||
.map(|s| WString::from_utf8_owned(s.to_string_lossy(encoding))),
|
||||
is_word_wrap: swf_tag.is_word_wrap,
|
||||
is_multiline: swf_tag.is_multiline,
|
||||
is_password: swf_tag.is_password,
|
||||
is_read_only: swf_tag.is_read_only,
|
||||
is_auto_size: swf_tag.is_auto_size,
|
||||
is_selectable: swf_tag.is_selectable,
|
||||
has_border: swf_tag.has_border,
|
||||
was_static: swf_tag.was_static,
|
||||
is_html: swf_tag.is_html,
|
||||
is_device_font: swf_tag.is_device_font,
|
||||
is_word_wrap: swf_tag.is_word_wrap(),
|
||||
is_multiline: swf_tag.is_multiline(),
|
||||
is_password: swf_tag.is_password(),
|
||||
is_read_only: swf_tag.is_read_only(),
|
||||
is_auto_size: swf_tag.is_auto_size(),
|
||||
is_selectable: swf_tag.is_selectable(),
|
||||
has_border: swf_tag.has_border(),
|
||||
was_static: swf_tag.was_static(),
|
||||
is_html: swf_tag.is_html(),
|
||||
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);
|
||||
} else {
|
||||
et.redraw_border(context.gc_context);
|
||||
|
@ -352,45 +352,16 @@ impl<'gc> EditText<'gc> {
|
|||
width: f64,
|
||||
height: f64,
|
||||
) -> Self {
|
||||
let swf_tag = swf::EditText {
|
||||
id: 0, //TODO: Dynamic text fields don't have a character ID?
|
||||
bounds: swf::Rectangle {
|
||||
let swf_tag = swf::EditText::new()
|
||||
.with_font_id(0, Twips::from_pixels(12.0))
|
||||
.with_color(Some(Color::BLACK))
|
||||
.with_bounds(swf::Rectangle {
|
||||
x_min: Twips::from_pixels(0.0),
|
||||
x_max: Twips::from_pixels(width),
|
||||
y_min: Twips::from_pixels(0.0),
|
||||
y_max: Twips::from_pixels(height),
|
||||
},
|
||||
font_id: None,
|
||||
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,
|
||||
};
|
||||
|
||||
})
|
||||
.with_layout(Default::default());
|
||||
let text_field = Self::from_swf_tag(context, swf_movie, swf_tag);
|
||||
|
||||
// Set position.
|
||||
|
|
|
@ -142,26 +142,26 @@ impl TextFormat {
|
|||
) -> Self {
|
||||
let encoding = swf_movie.encoding();
|
||||
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
|
||||
.font_class_name
|
||||
.font_class()
|
||||
.map(|s| WString::from_utf8(&s.to_string_lossy(encoding)))
|
||||
.or_else(|| font.map(|font| WString::from_utf8(font.descriptor().class())))
|
||||
.unwrap_or_else(|| WString::from_utf8("Times New Roman"));
|
||||
let align = et.layout.as_ref().map(|l| l.align);
|
||||
let left_margin = et.layout.as_ref().map(|l| l.left_margin.to_pixels());
|
||||
let right_margin = et.layout.as_ref().map(|l| l.right_margin.to_pixels());
|
||||
let indent = et.layout.as_ref().map(|l| l.indent.to_pixels());
|
||||
let leading = et.layout.map(|l| l.leading.to_pixels());
|
||||
let align = et.layout().map(|l| l.align);
|
||||
let left_margin = et.layout().map(|l| l.left_margin.to_pixels());
|
||||
let right_margin = et.layout().map(|l| l.right_margin.to_pixels());
|
||||
let indent = et.layout().map(|l| l.indent.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
|
||||
// Times New Roman non-bold, non-italic. This will need to be revised
|
||||
// when we start supporting device fonts.
|
||||
Self {
|
||||
font: Some(font_class),
|
||||
size: et.height.map(|h| h.to_pixels()),
|
||||
size: et.height().map(|h| h.to_pixels()),
|
||||
color: et
|
||||
.color
|
||||
.color()
|
||||
.map(|color| swf::Color::from_rgb(color.to_rgb(), 0)),
|
||||
align,
|
||||
bold: Some(font.map(|font| font.descriptor().bold()).unwrap_or(false)),
|
||||
|
|
|
@ -2348,72 +2348,68 @@ impl<'a> Reader<'a> {
|
|||
pub fn read_define_edit_text(&mut self) -> Result<EditText<'a>> {
|
||||
let id = self.read_character_id()?;
|
||||
let bounds = self.read_rectangle()?;
|
||||
let flags = self.read_u8()?;
|
||||
let flags2 = self.read_u8()?;
|
||||
let font_id = if flags & 0b1 != 0 {
|
||||
Some(self.read_character_id()?)
|
||||
let flags = EditTextFlag::from_bits_truncate(self.read_u16()?);
|
||||
let font_id = if flags.contains(EditTextFlag::HAS_FONT) {
|
||||
self.read_character_id()?
|
||||
} else {
|
||||
None
|
||||
Default::default()
|
||||
};
|
||||
let font_class_name = if flags2 & 0b10000000 != 0 {
|
||||
Some(self.read_str()?)
|
||||
let font_class = if flags.contains(EditTextFlag::HAS_FONT_CLASS) {
|
||||
self.read_str()?
|
||||
} else {
|
||||
None
|
||||
Default::default()
|
||||
};
|
||||
let height = if flags & 0b1 != 0 {
|
||||
Some(Twips::new(self.read_u16()?))
|
||||
let height = if flags.contains(EditTextFlag::HAS_FONT) {
|
||||
Twips::new(self.read_u16()?)
|
||||
} else {
|
||||
None
|
||||
Twips::ZERO
|
||||
};
|
||||
let color = if flags & 0b100 != 0 {
|
||||
Some(self.read_rgba()?)
|
||||
let color = if flags.contains(EditTextFlag::HAS_TEXT_COLOR) {
|
||||
self.read_rgba()?
|
||||
} else {
|
||||
None
|
||||
Color::BLACK
|
||||
};
|
||||
let max_length = if flags & 0b10 != 0 {
|
||||
Some(self.read_u16()?)
|
||||
let max_length = if flags.contains(EditTextFlag::HAS_MAX_LENGTH) {
|
||||
self.read_u16()?
|
||||
} else {
|
||||
None
|
||||
0
|
||||
};
|
||||
let layout = if flags2 & 0b100000 != 0 {
|
||||
Some(TextLayout {
|
||||
let layout = if flags.contains(EditTextFlag::HAS_LAYOUT) {
|
||||
TextLayout {
|
||||
align: TextAlign::from_u8(self.read_u8()?)
|
||||
.ok_or_else(|| Error::invalid_data("Invalid edit text alignment"))?,
|
||||
left_margin: Twips::new(self.read_u16()?),
|
||||
right_margin: Twips::new(self.read_u16()?),
|
||||
indent: Twips::new(self.read_u16()?),
|
||||
leading: Twips::new(self.read_i16()?),
|
||||
})
|
||||
}
|
||||
} 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 initial_text = if flags & 0b10000000 != 0 {
|
||||
Some(self.read_str()?)
|
||||
let initial_text = if flags.contains(EditTextFlag::HAS_TEXT) {
|
||||
self.read_str()?
|
||||
} else {
|
||||
None
|
||||
Default::default()
|
||||
};
|
||||
Ok(EditText {
|
||||
id,
|
||||
bounds,
|
||||
font_id,
|
||||
font_class_name,
|
||||
font_class,
|
||||
height,
|
||||
color,
|
||||
max_length,
|
||||
layout,
|
||||
variable_name,
|
||||
initial_text,
|
||||
is_word_wrap: flags & 0b1000000 != 0,
|
||||
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,
|
||||
flags,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -359,44 +359,40 @@ pub fn tag_tests() -> Vec<TagTestData> {
|
|||
),
|
||||
(
|
||||
4,
|
||||
Tag::DefineEditText(Box::new(EditText {
|
||||
id: 2,
|
||||
bounds: Rectangle {
|
||||
x_min: Twips::from_pixels(-2.0),
|
||||
x_max: Twips::from_pixels(77.9),
|
||||
y_min: Twips::from_pixels(-2.0),
|
||||
y_max: Twips::from_pixels(23.9),
|
||||
},
|
||||
font_id: Some(1),
|
||||
font_class_name: None,
|
||||
height: Some(Twips::from_pixels(18.0)),
|
||||
color: Some(Color {
|
||||
r: 0,
|
||||
g: 255,
|
||||
b: 0,
|
||||
a: 255,
|
||||
}),
|
||||
max_length: None,
|
||||
layout: Some(TextLayout {
|
||||
align: TextAlign::Justify,
|
||||
left_margin: Twips::from_pixels(3.0),
|
||||
right_margin: Twips::from_pixels(4.0),
|
||||
indent: Twips::from_pixels(1.0),
|
||||
leading: Twips::from_pixels(2.0),
|
||||
}),
|
||||
variable_name: SwfStr::from_str_with_encoding("foo", WINDOWS_1252).unwrap(),
|
||||
initial_text: Some(SwfStr::from_str_with_encoding("-_-", WINDOWS_1252).unwrap()),
|
||||
is_word_wrap: false,
|
||||
is_multiline: true,
|
||||
is_password: false,
|
||||
is_read_only: true,
|
||||
is_auto_size: false,
|
||||
is_selectable: true,
|
||||
has_border: true,
|
||||
was_static: false,
|
||||
is_html: false,
|
||||
is_device_font: true,
|
||||
})),
|
||||
Tag::DefineEditText(Box::new(
|
||||
EditText::new()
|
||||
.with_id(2)
|
||||
.with_font_id(1, Twips::from_pixels(18.0))
|
||||
.with_bounds(Rectangle {
|
||||
x_min: Twips::from_pixels(-2.0),
|
||||
x_max: Twips::from_pixels(77.9),
|
||||
y_min: Twips::from_pixels(-2.0),
|
||||
y_max: Twips::from_pixels(23.9),
|
||||
})
|
||||
.with_color(Some(Color {
|
||||
r: 0,
|
||||
g: 255,
|
||||
b: 0,
|
||||
a: 255,
|
||||
}))
|
||||
.with_layout(Some(TextLayout {
|
||||
align: TextAlign::Justify,
|
||||
left_margin: Twips::from_pixels(3.0),
|
||||
right_margin: Twips::from_pixels(4.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(),
|
||||
)
|
||||
.with_initial_text(Some(
|
||||
SwfStr::from_str_with_encoding("-_-", WINDOWS_1252).unwrap(),
|
||||
))
|
||||
.with_is_read_only(true)
|
||||
.with_has_border(true)
|
||||
.with_is_multiline(true)
|
||||
.with_use_outlines(false),
|
||||
)),
|
||||
read_tag_bytes_from_file("tests/swfs/DefineEditText-MX.swf", TagCode::DefineEditText),
|
||||
),
|
||||
(
|
||||
|
|
356
swf/src/types.rs
356
swf/src/types.rs
|
@ -1337,29 +1337,340 @@ pub struct GlyphEntry {
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct EditText<'a> {
|
||||
pub id: CharacterId,
|
||||
pub bounds: Rectangle,
|
||||
pub font_id: Option<CharacterId>, // TODO(Herschel): Combine with height
|
||||
pub font_class_name: Option<&'a SwfStr>,
|
||||
pub height: Option<Twips>,
|
||||
pub color: Option<Color>,
|
||||
pub max_length: Option<u16>,
|
||||
pub layout: Option<TextLayout>,
|
||||
pub variable_name: &'a SwfStr,
|
||||
pub initial_text: Option<&'a SwfStr>,
|
||||
pub is_word_wrap: bool,
|
||||
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,
|
||||
pub(crate) id: CharacterId,
|
||||
pub(crate) bounds: Rectangle,
|
||||
pub(crate) font_id: CharacterId,
|
||||
pub(crate) font_class: &'a SwfStr,
|
||||
pub(crate) height: Twips,
|
||||
pub(crate) color: Color,
|
||||
pub(crate) max_length: u16,
|
||||
pub(crate) layout: TextLayout,
|
||||
pub(crate) variable_name: &'a SwfStr,
|
||||
pub(crate) initial_text: &'a SwfStr,
|
||||
pub(crate) flags: EditTextFlag,
|
||||
}
|
||||
|
||||
#[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 align: TextAlign,
|
||||
pub left_margin: Twips,
|
||||
|
@ -1368,8 +1679,9 @@ pub struct TextLayout {
|
|||
pub leading: Twips,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, FromPrimitive, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, FromPrimitive, PartialEq)]
|
||||
pub enum TextAlign {
|
||||
#[default]
|
||||
Left = 0,
|
||||
Right = 1,
|
||||
Center = 2,
|
||||
|
|
|
@ -2262,63 +2262,31 @@ impl<W: Write> Writer<W> {
|
|||
let mut writer = Writer::new(&mut buf, self.version);
|
||||
writer.write_character_id(edit_text.id)?;
|
||||
writer.write_rectangle(&edit_text.bounds)?;
|
||||
let flags = if edit_text.initial_text.is_some() {
|
||||
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_u16(edit_text.flags.bits() as u16)?;
|
||||
|
||||
writer.write_u8(flags)?;
|
||||
writer.write_u8(flags2)?;
|
||||
|
||||
if let Some(font_id) = edit_text.font_id {
|
||||
if let Some(font_id) = edit_text.font_id() {
|
||||
writer.write_character_id(font_id)?;
|
||||
}
|
||||
|
||||
// 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)?;
|
||||
}
|
||||
|
||||
// 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)?
|
||||
}
|
||||
|
||||
if let Some(ref color) = edit_text.color {
|
||||
if let Some(color) = edit_text.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)?;
|
||||
}
|
||||
|
||||
if let Some(ref layout) = edit_text.layout {
|
||||
if let Some(layout) = edit_text.layout() {
|
||||
writer.write_u8(layout.align as u8)?;
|
||||
writer.write_u16(layout.left_margin.get() as u16)?; // TODO: Handle overflow
|
||||
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)?;
|
||||
if let Some(text) = edit_text.initial_text {
|
||||
|
||||
if let Some(text) = edit_text.initial_text() {
|
||||
writer.write_string(text)?;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue