Skip to content

Commit

Permalink
debug_ui: Improve layout debug boxes
Browse files Browse the repository at this point in the history
Displaying all at once would be a mess, so this patch adds
a way of enabling and disabling specific types of layout
debug boxes.
  • Loading branch information
kjarosh authored and Dinnerbone committed Oct 15, 2024
1 parent e673273 commit 1dc9085
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 44 deletions.
27 changes: 19 additions & 8 deletions core/src/debug_ui/display_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use crate::debug_ui::handle::{AVM1ObjectHandle, AVM2ObjectHandle, DisplayObjectH
use crate::debug_ui::movie::open_movie_button;
use crate::debug_ui::Message;
use crate::display_object::{
AutoSizeMode, Bitmap, DisplayObject, EditText, InteractiveObject, MovieClip, Stage,
TDisplayObject, TDisplayObjectContainer, TInteractiveObject,
AutoSizeMode, Bitmap, DisplayObject, EditText, InteractiveObject, LayoutDebugBoxesFlag,
MovieClip, Stage, TDisplayObject, TDisplayObjectContainer, TInteractiveObject,
};
use crate::focus_tracker::Highlight;
use egui::collapsing_header::CollapsingState;
Expand Down Expand Up @@ -464,12 +464,23 @@ impl DisplayObjectWindow {
}
ui.end_row();

ui.label("Draw Layout Boxes");
ui.horizontal(|ui| {
let mut draw_layout_boxes = object.draw_layout_boxes();
ui.checkbox(&mut draw_layout_boxes, "Enabled");
if draw_layout_boxes != object.draw_layout_boxes() {
object.set_draw_layout_boxes(context, draw_layout_boxes);
ui.label("Layout Debug Boxes");
ui.vertical(|ui| {
for (name, flag) in [
("Text Exterior", LayoutDebugBoxesFlag::TEXT_EXTERIOR),
("Text", LayoutDebugBoxesFlag::TEXT),
("Line", LayoutDebugBoxesFlag::LINE),
("Line Interior", LayoutDebugBoxesFlag::LINE_INTERIOR),
("Box", LayoutDebugBoxesFlag::BOX),
("Box Interior", LayoutDebugBoxesFlag::BOX_INTERIOR),
("Character", LayoutDebugBoxesFlag::CHAR),
] {
let old_value = object.layout_debug_boxes_flag(flag);
let mut value = old_value;
ui.checkbox(&mut value, name);
if value != old_value {
object.set_layout_debug_boxes_flag(context, flag, value);
}
}
});
ui.end_row();
Expand Down
2 changes: 2 additions & 0 deletions core/src/display_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub use crate::display_object::container::{
pub use avm1_button::{Avm1Button, ButtonState, ButtonTracking};
pub use avm2_button::Avm2Button;
pub use bitmap::{Bitmap, BitmapClass};
#[allow(unused)]
pub use edit_text::LayoutDebugBoxesFlag;
pub use edit_text::{AutoSizeMode, EditText, TextSelection};
pub use graphic::Graphic;
pub use interactive::{Avm2MousePick, InteractiveObject, TInteractiveObject};
Expand Down
114 changes: 78 additions & 36 deletions core/src/display_object/edit_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ pub struct EditTextData<'gc> {
#[collect(require_static)]
flags: EditTextFlag,

/// Flags specifying how layout debug boxes should be drawn.
#[collect(require_static)]
layout_debug_boxes_flags: LayoutDebugBoxesFlag,

/// Whether this EditText represents an AVM2 TextLine.
is_tlf: bool,

Expand Down Expand Up @@ -304,6 +308,7 @@ impl<'gc> EditText<'gc> {
is_tlf: false,
restrict: EditTextRestrict::allow_all(),
last_click: None,
layout_debug_boxes_flags: LayoutDebugBoxesFlag::empty(),
},
));

Expand Down Expand Up @@ -625,18 +630,20 @@ impl<'gc> EditText<'gc> {
self.0.write(gc_context).is_tlf = is_tlf;
}

pub fn draw_layout_boxes(self) -> bool {
self.0
.read()
.flags
.contains(EditTextFlag::DRAW_LAYOUT_BOXES)
pub fn layout_debug_boxes_flag(self, flag: LayoutDebugBoxesFlag) -> bool {
self.0.read().layout_debug_boxes_flags.contains(flag)
}

pub fn set_draw_layout_boxes(self, context: &mut UpdateContext<'gc>, value: bool) {
pub fn set_layout_debug_boxes_flag(
self,
context: &mut UpdateContext<'gc>,
flag: LayoutDebugBoxesFlag,
value: bool,
) {
self.0
.write(context.gc())
.flags
.set(EditTextFlag::DRAW_LAYOUT_BOXES, value);
.layout_debug_boxes_flags
.set(flag, value);
}

pub fn replace_text(
Expand Down Expand Up @@ -895,6 +902,48 @@ impl<'gc> EditText<'gc> {
}
}

fn render_debug_boxes(
self,
context: &mut RenderContext<'_, 'gc>,
flags: LayoutDebugBoxesFlag,
layout: &Layout<'gc>,
) {
if flags.contains(LayoutDebugBoxesFlag::CHAR) {
let text = &self.text();
for i in 0..text.len() {
if let Some(bounds) = layout.char_bounds(i, text) {
context.draw_rect_outline(Color::MAGENTA, bounds, Twips::ONE);
}
}
}
if flags.contains(LayoutDebugBoxesFlag::BOX_INTERIOR) {
for lbox in layout.boxes_iter() {
context.draw_rect_outline(Color::RED, lbox.interior_bounds().into(), Twips::ONE);
}
}
if flags.contains(LayoutDebugBoxesFlag::BOX) {
for lbox in layout.boxes_iter() {
context.draw_rect_outline(Color::RED, lbox.bounds().into(), Twips::ONE);
}
}
if flags.contains(LayoutDebugBoxesFlag::LINE_INTERIOR) {
for line in layout.lines() {
context.draw_rect_outline(Color::BLUE, line.interior_bounds().into(), Twips::ONE);
}
}
if flags.contains(LayoutDebugBoxesFlag::LINE) {
for line in layout.lines() {
context.draw_rect_outline(Color::BLUE, line.bounds().into(), Twips::ONE);
}
}
if flags.contains(LayoutDebugBoxesFlag::TEXT) {
context.draw_rect_outline(Color::GREEN, layout.bounds().into(), Twips::ONE);
}
if flags.contains(LayoutDebugBoxesFlag::TEXT_EXTERIOR) {
context.draw_rect_outline(Color::GREEN, layout.exterior_bounds().into(), Twips::ONE);
}
}

/// Render a layout box, plus its children.
fn render_layout_box(self, context: &mut RenderContext<'_, 'gc>, lbox: &LayoutBox<'gc>) {
let origin = lbox.interior_bounds().origin();
Expand Down Expand Up @@ -2328,35 +2377,16 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
..Default::default()
});

{
let draw_boxes = edit_text.flags.contains(EditTextFlag::DRAW_LAYOUT_BOXES);
if draw_boxes {
context.draw_rect_outline(
Color::GREEN,
edit_text.layout.exterior_bounds().into(),
Twips::ONE,
);

let text = &self.text();
for i in 0..text.len() {
if let Some(bounds) = edit_text.layout.char_bounds(i, text) {
context.draw_rect_outline(Color::MAGENTA, bounds, Twips::ONE);
}
}
}

for layout_box in edit_text.layout.boxes_iter() {
if draw_boxes {
context.draw_rect_outline(
Color::RED,
layout_box.interior_bounds().into(),
Twips::ONE,
);
}
self.render_layout_box(context, layout_box);
}
for layout_box in edit_text.layout.boxes_iter() {
self.render_layout_box(context, layout_box);
}

self.render_debug_boxes(
context,
edit_text.layout_debug_boxes_flags,
&edit_text.layout,
);

context.transform_stack.pop();

context.commands.deactivate_mask();
Expand Down Expand Up @@ -2734,7 +2764,6 @@ bitflags::bitflags! {
struct EditTextFlag: u16 {
const FIRING_VARIABLE_BINDING = 1 << 0;
const HAS_BACKGROUND = 1 << 1;
const DRAW_LAYOUT_BOXES = 1 << 2;
const CONDENSE_WHITE = 1 << 13;
const ALWAYS_SHOW_SELECTION = 1 << 14;

Expand All @@ -2753,6 +2782,19 @@ bitflags::bitflags! {
}
}

bitflags::bitflags! {
#[derive(Clone, Copy)]
pub struct LayoutDebugBoxesFlag: u8 {
const TEXT_EXTERIOR = 1 << 1;
const TEXT = 1 << 2;
const LINE = 1 << 3;
const LINE_INTERIOR = 1 << 4;
const BOX = 1 << 5;
const BOX_INTERIOR = 1 << 6;
const CHAR = 1 << 7;
}
}

/// Static data shared between all instances of a text object.
#[derive(Debug, Clone, Collect)]
#[collect(require_static)]
Expand Down

0 comments on commit 1dc9085

Please sign in to comment.