Replace the existing default format on `EditText` with our brand-new `FormatSpans`.
This also includes code to automatically populate the default format with data from the SWF tag.
This commit is contained in:
parent
efdecdea64
commit
4eca2d4bdd
|
@ -4,7 +4,7 @@ use crate::avm1::{Avm1, Object, StageObject, Value};
|
||||||
use crate::context::{RenderContext, UpdateContext};
|
use crate::context::{RenderContext, UpdateContext};
|
||||||
use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
use crate::display_object::{DisplayObjectBase, TDisplayObject};
|
||||||
use crate::font::{Font, Glyph};
|
use crate::font::{Font, Glyph};
|
||||||
use crate::html::TextFormat;
|
use crate::html::{FormatSpans, TextFormat};
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::tag_utils::SwfMovie;
|
use crate::tag_utils::SwfMovie;
|
||||||
|
@ -42,10 +42,22 @@ pub struct EditTextData<'gc> {
|
||||||
text: String,
|
text: String,
|
||||||
|
|
||||||
/// The current HTML document displayed by this `EditText`.
|
/// The current HTML document displayed by this `EditText`.
|
||||||
|
///
|
||||||
|
/// The HTML representation of this `EditText` is lowered into an
|
||||||
|
/// appropriate set of format spans, which is used for actual rendering.
|
||||||
|
/// The HTML is only retained if there is also a stylesheet already defined
|
||||||
|
/// on the `EditText`, else it is discarded during the lowering process.
|
||||||
document: XMLDocument<'gc>,
|
document: XMLDocument<'gc>,
|
||||||
|
|
||||||
/// The text formatting for newly inserted text spans.
|
/// The underlying text format spans of the `EditText`.
|
||||||
new_format: TextFormat,
|
///
|
||||||
|
/// This is generated from HTML (with optional CSS) or set directly, and
|
||||||
|
/// can be directly manipulated by ActionScript. It can also be raised to
|
||||||
|
/// an equivalent HTML representation, as long as no stylesheet is present.
|
||||||
|
///
|
||||||
|
/// It is lowered further into layout boxes, which are used for actual
|
||||||
|
/// rendering.
|
||||||
|
text_spans: FormatSpans,
|
||||||
|
|
||||||
/// If the text is in multi-line mode or single-line mode.
|
/// If the text is in multi-line mode or single-line mode.
|
||||||
is_multiline: bool,
|
is_multiline: bool,
|
||||||
|
@ -71,6 +83,7 @@ impl<'gc> EditText<'gc> {
|
||||||
let is_word_wrap = swf_tag.is_word_wrap;
|
let is_word_wrap = swf_tag.is_word_wrap;
|
||||||
let document = XMLDocument::new(context.gc_context);
|
let document = XMLDocument::new(context.gc_context);
|
||||||
let text = swf_tag.initial_text.clone().unwrap_or_default();
|
let text = swf_tag.initial_text.clone().unwrap_or_default();
|
||||||
|
let default_format = TextFormat::from_swf_tag(swf_tag.clone(), swf_movie.clone(), context);
|
||||||
|
|
||||||
if swf_tag.is_html {
|
if swf_tag.is_html {
|
||||||
document
|
document
|
||||||
|
@ -91,7 +104,7 @@ impl<'gc> EditText<'gc> {
|
||||||
base: Default::default(),
|
base: Default::default(),
|
||||||
text,
|
text,
|
||||||
document,
|
document,
|
||||||
new_format: TextFormat::default(),
|
text_spans: FormatSpans::from_str_and_format("", default_format),
|
||||||
static_data: gc_arena::Gc::allocate(
|
static_data: gc_arena::Gc::allocate(
|
||||||
context.gc_context,
|
context.gc_context,
|
||||||
EditTextStatic {
|
EditTextStatic {
|
||||||
|
@ -192,12 +205,12 @@ impl<'gc> EditText<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_text_format(self) -> TextFormat {
|
pub fn new_text_format(self) -> TextFormat {
|
||||||
self.0.read().new_format.clone()
|
self.0.read().text_spans.default_format().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_new_text_format(self, tf: TextFormat, gc_context: MutationContext<'gc, '_>) {
|
pub fn set_new_text_format(self, tf: TextFormat, gc_context: MutationContext<'gc, '_>) {
|
||||||
self.0.write(gc_context).cached_break_points = None;
|
self.0.write(gc_context).cached_break_points = None;
|
||||||
self.0.write(gc_context).new_format = tf;
|
self.0.write(gc_context).text_spans.set_default_format(tf);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_multiline(self) -> bool {
|
pub fn is_multiline(self) -> bool {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
mod dimensions;
|
mod dimensions;
|
||||||
mod text_format;
|
mod text_format;
|
||||||
|
|
||||||
pub use text_format::TextFormat;
|
pub use text_format::{FormatSpans, TextFormat};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
//! Classes that store formatting options
|
//! Classes that store formatting options
|
||||||
use crate::avm1::{Avm1, Object, ScriptObject, TObject, Value};
|
use crate::avm1::{Avm1, Object, ScriptObject, TObject, Value};
|
||||||
use crate::context::UpdateContext;
|
use crate::context::UpdateContext;
|
||||||
|
use crate::tag_utils::SwfMovie;
|
||||||
use gc_arena::Collect;
|
use gc_arena::Collect;
|
||||||
use std::cmp::{min, Ordering};
|
use std::cmp::{min, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// A set of text formatting options to be applied to some part, or the whole
|
/// A set of text formatting options to be applied to some part, or the whole
|
||||||
/// of, a given text field.
|
/// of, a given text field.
|
||||||
|
@ -101,6 +103,50 @@ fn getbool_from_avm1_object<'gc>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextFormat {
|
impl TextFormat {
|
||||||
|
/// Construct a `TextFormat` from an `EditText`'s SWF tag.
|
||||||
|
///
|
||||||
|
/// This requires an `UpdateContext` as we will need to retrieve some font
|
||||||
|
/// information from the actually-referenced font.
|
||||||
|
pub fn from_swf_tag<'gc>(
|
||||||
|
et: swf::EditText,
|
||||||
|
swf_movie: Arc<SwfMovie>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
) -> Self {
|
||||||
|
let movie_library = context.library.library_for_movie_mut(swf_movie);
|
||||||
|
|
||||||
|
//TODO: How do we represent fonts referenced by character rather than
|
||||||
|
//by linkage name?
|
||||||
|
let font = et.font_class_name;
|
||||||
|
let align = et.layout.clone().map(|l| l.align);
|
||||||
|
let left_margin = et.layout.clone().map(|l| l.left_margin.to_pixels());
|
||||||
|
let right_margin = et.layout.clone().map(|l| l.right_margin.to_pixels());
|
||||||
|
let indent = et.layout.clone().map(|l| l.indent.to_pixels());
|
||||||
|
let leading = et.layout.map(|l| l.leading.to_pixels());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
font,
|
||||||
|
size: et.height.map(|h| h.to_pixels()),
|
||||||
|
color: et.color,
|
||||||
|
align,
|
||||||
|
bold: None, // TODO: Resolve a font and pull this from that font
|
||||||
|
italic: None, // TODO: Resolve a font and pull this from that font
|
||||||
|
underline: None, // TODO: Resolve a font and pull this from that font
|
||||||
|
left_margin,
|
||||||
|
right_margin,
|
||||||
|
indent,
|
||||||
|
block_indent: Some(0.0), // TODO: This isn't specified by the tag itself
|
||||||
|
kerning: Some(true), // TODO: this isn't specified by the tag itself
|
||||||
|
leading,
|
||||||
|
letter_spacing: Some(0.0), // TODO: This isn't specified by the tag itself
|
||||||
|
tab_stops: Some(vec![]), // TODO: Are there default tab stops?
|
||||||
|
bullet: Some(false), // TODO: Default tab stops?
|
||||||
|
|
||||||
|
// TODO: These are probably empty strings by default
|
||||||
|
url: Some("".to_string()),
|
||||||
|
target: Some("".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a `TextFormat` from an object that is
|
/// Construct a `TextFormat` from an object that is
|
||||||
pub fn from_avm1_object<'gc>(
|
pub fn from_avm1_object<'gc>(
|
||||||
object1: Object<'gc>,
|
object1: Object<'gc>,
|
||||||
|
@ -643,6 +689,14 @@ impl FormatSpans {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_format(&self) -> &TextFormat {
|
||||||
|
&self.default_format
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_default_format(&mut self, tf: TextFormat) {
|
||||||
|
self.default_format = tf;
|
||||||
|
}
|
||||||
|
|
||||||
/// Find the index of the span that covers a given search position.
|
/// Find the index of the span that covers a given search position.
|
||||||
///
|
///
|
||||||
/// This function returns both the index of the span which covers the
|
/// This function returns both the index of the span which covers the
|
||||||
|
|
Loading…
Reference in New Issue