Add ability to debug element trees as JSON

This commit is contained in:
Nathan Sobo 2021-04-06 23:50:13 -06:00
parent 57a3207897
commit 0664321125
25 changed files with 554 additions and 41 deletions

6
Cargo.lock generated
View File

@ -930,6 +930,8 @@ dependencies = [
"rand 0.8.3",
"replace_with",
"resvg",
"serde",
"serde_json",
"simplelog",
"smallvec",
"smol",
@ -1691,9 +1693,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.124"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f"
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
[[package]]
name = "serde_json"

View File

@ -18,6 +18,8 @@ pathfinder_geometry = "0.5"
rand = "0.8.3"
replace_with = "0.1.7"
resvg = "0.14"
serde = "1.0.125"
serde_json = "1.0.64"
smallvec = "1.6.1"
smol = "1.2"
tiny-skia = "0.5"

View File

@ -2,9 +2,10 @@ use gpui::{
color::ColorU,
fonts::{Properties, Weight},
platform::{current as platform, Runner},
Element as _, Quad,
DebugContext, Element as _, Quad,
};
use log::LevelFilter;
use pathfinder_geometry::rect::RectF;
use simplelog::SimpleLogger;
fn main() {
@ -59,7 +60,7 @@ impl gpui::Element for TextElement {
fn paint(
&mut self,
bounds: pathfinder_geometry::rect::RectF,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut gpui::PaintContext,
) -> Self::PaintState {
@ -109,11 +110,21 @@ impl gpui::Element for TextElement {
fn dispatch_event(
&mut self,
_: &gpui::Event,
_: pathfinder_geometry::rect::RectF,
_: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
_: &mut gpui::EventContext,
) -> bool {
false
}
fn debug(
&self,
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
_: &DebugContext,
) -> gpui::json::Value {
todo!()
}
}

9
gpui/src/color.rs Normal file
View File

@ -0,0 +1,9 @@
use crate::json::ToJson;
pub use pathfinder_color::*;
use serde_json::json;
impl ToJson for ColorU {
fn to_json(&self) -> serde_json::Value {
json!(format!("0x{:x}{:x}{:x}", self.r, self.g, self.b))
}
}

View File

@ -1,8 +1,10 @@
use crate::{
AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
json, AfterLayoutContext, DebugContext, Element, ElementBox, Event, EventContext,
LayoutContext, PaintContext, SizeConstraint,
};
use json::ToJson;
use pathfinder_geometry::vector::{vec2f, Vector2F};
use serde_json::json;
pub struct Align {
child: ElementBox,
@ -79,4 +81,19 @@ impl Element for Align {
) -> bool {
self.child.dispatch_event(event, ctx)
}
fn debug(
&self,
bounds: pathfinder_geometry::rect::RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
) -> json::Value {
json!({
"type": "Align",
"alignment": self.alignment.to_json(),
"bounds": bounds.to_json(),
"child": self.child.debug(ctx),
})
}
}

View File

@ -1,5 +1,9 @@
use super::Element;
use crate::PaintContext;
use crate::{
json::{self, json},
DebugContext, PaintContext,
};
use json::ToJson;
use pathfinder_geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
@ -70,4 +74,14 @@ where
) -> bool {
false
}
fn debug(
&self,
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
_: &DebugContext,
) -> json::Value {
json!({"type": "Canvas", "bounds": bounds.to_json()})
}
}

View File

@ -1,8 +1,11 @@
use json::ToJson;
use serde_json::json;
use crate::{
AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
geometry::{rect::RectF, vector::Vector2F},
json, AfterLayoutContext, DebugContext, Element, ElementBox, Event, EventContext,
LayoutContext, PaintContext, SizeConstraint,
};
use pathfinder_geometry::vector::Vector2F;
pub struct ConstrainedBox {
child: ElementBox,
@ -63,7 +66,7 @@ impl Element for ConstrainedBox {
fn paint(
&mut self,
bounds: pathfinder_geometry::rect::RectF,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
) -> Self::PaintState {
@ -73,11 +76,21 @@ impl Element for ConstrainedBox {
fn dispatch_event(
&mut self,
event: &Event,
_: pathfinder_geometry::rect::RectF,
_: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
) -> bool {
self.child.dispatch_event(event, ctx)
}
fn debug(
&self,
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
) -> json::Value {
json!({"type": "ConstrainedBox", "constraint": self.constraint.to_json(), "child": self.child.debug(ctx)})
}
}

View File

@ -1,8 +1,10 @@
use pathfinder_geometry::rect::RectF;
use serde_json::json;
use crate::{
color::ColorU,
geometry::vector::{vec2f, Vector2F},
json::ToJson,
scene::{self, Border, Quad},
AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
@ -189,6 +191,28 @@ impl Element for Container {
) -> bool {
self.child.dispatch_event(event, ctx)
}
fn debug(
&self,
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &crate::DebugContext,
) -> serde_json::Value {
json!({
"type": "Container",
"details": {
"margin": self.margin.to_json(),
"padding": self.padding.to_json(),
"background_color": self.background_color.to_json(),
"border": self.border.to_json(),
"corner_radius": self.corner_radius,
"shadow": self.shadow.to_json(),
},
"bounds": bounds.to_json(),
"child": self.child.debug(ctx),
})
}
}
#[derive(Default)]
@ -199,6 +223,25 @@ pub struct Margin {
right: f32,
}
impl ToJson for Margin {
fn to_json(&self) -> serde_json::Value {
let mut value = json!({});
if self.top > 0. {
value["top"] = json!(self.top);
}
if self.right > 0. {
value["right"] = json!(self.right);
}
if self.bottom > 0. {
value["bottom"] = json!(self.bottom);
}
if self.left > 0. {
value["left"] = json!(self.left);
}
value
}
}
#[derive(Default)]
pub struct Padding {
top: f32,
@ -207,9 +250,38 @@ pub struct Padding {
right: f32,
}
impl ToJson for Padding {
fn to_json(&self) -> serde_json::Value {
let mut value = json!({});
if self.top > 0. {
value["top"] = json!(self.top);
}
if self.right > 0. {
value["right"] = json!(self.right);
}
if self.bottom > 0. {
value["bottom"] = json!(self.bottom);
}
if self.left > 0. {
value["left"] = json!(self.left);
}
value
}
}
#[derive(Default)]
pub struct Shadow {
offset: Vector2F,
blur: f32,
color: ColorU,
}
impl ToJson for Shadow {
fn to_json(&self) -> serde_json::Value {
json!({
"offset": self.offset.to_json(),
"blur": self.blur,
"color": self.color.to_json()
})
}
}

View File

@ -1,6 +1,10 @@
use crate::geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
use crate::{
geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
},
json::{json, ToJson},
DebugContext,
};
use crate::{
AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
@ -58,4 +62,17 @@ impl Element for Empty {
) -> bool {
false
}
fn debug(
&self,
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
_: &DebugContext,
) -> serde_json::Value {
json!({
"type": "Empty",
"bounds": bounds.to_json(),
})
}
}

View File

@ -1,6 +1,9 @@
use pathfinder_geometry::rect::RectF;
use serde_json::json;
use crate::{
geometry::vector::Vector2F, AfterLayoutContext, Element, ElementBox, Event, EventContext,
LayoutContext, PaintContext, SizeConstraint,
geometry::vector::Vector2F, AfterLayoutContext, DebugContext, Element, ElementBox, Event,
EventContext, LayoutContext, PaintContext, SizeConstraint,
};
pub struct EventHandler {
@ -49,7 +52,7 @@ impl Element for EventHandler {
fn paint(
&mut self,
bounds: pathfinder_geometry::rect::RectF,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
) -> Self::PaintState {
@ -59,7 +62,7 @@ impl Element for EventHandler {
fn dispatch_event(
&mut self,
event: &Event,
bounds: pathfinder_geometry::rect::RectF,
bounds: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
@ -80,4 +83,17 @@ impl Element for EventHandler {
}
}
}
fn debug(
&self,
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
) -> serde_json::Value {
json!({
"type": "EventHandler",
"child": self.child.debug(ctx),
})
}
}

View File

@ -1,10 +1,15 @@
use std::any::Any;
use crate::{
AfterLayoutContext, Axis, Element, ElementBox, Event, EventContext, LayoutContext,
PaintContext, SizeConstraint, Vector2FExt,
json::{self, ToJson, Value},
AfterLayoutContext, Axis, DebugContext, Element, ElementBox, Event, EventContext,
LayoutContext, PaintContext, SizeConstraint, Vector2FExt,
};
use pathfinder_geometry::vector::{vec2f, Vector2F};
use pathfinder_geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
};
use serde_json::json;
pub struct Flex {
axis: Axis,
@ -130,7 +135,7 @@ impl Element for Flex {
fn paint(
&mut self,
bounds: pathfinder_geometry::rect::RectF,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
) -> Self::PaintState {
@ -147,7 +152,7 @@ impl Element for Flex {
fn dispatch_event(
&mut self,
event: &Event,
_: pathfinder_geometry::rect::RectF,
_: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
@ -158,6 +163,21 @@ impl Element for Flex {
}
handled
}
fn debug(
&self,
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
) -> json::Value {
json!({
"type": "Flex",
"axis": self.axis.to_json(),
"bounds": bounds.to_json(),
"children": self.children.iter().map(|child| child.debug(ctx)).collect::<Vec<json::Value>>()
})
}
}
struct FlexParentData {
@ -202,7 +222,7 @@ impl Element for Expanded {
fn paint(
&mut self,
bounds: pathfinder_geometry::rect::RectF,
bounds: RectF,
_: &mut Self::LayoutState,
ctx: &mut PaintContext,
) -> Self::PaintState {
@ -212,7 +232,7 @@ impl Element for Expanded {
fn dispatch_event(
&mut self,
event: &Event,
_: pathfinder_geometry::rect::RectF,
_: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
ctx: &mut EventContext,
@ -223,4 +243,18 @@ impl Element for Expanded {
fn metadata(&self) -> Option<&dyn Any> {
Some(&self.metadata)
}
fn debug(
&self,
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
) -> Value {
json!({
"type": "Expanded",
"flex": self.metadata.flex,
"child": self.child.debug(ctx)
})
}
}

View File

@ -1,3 +1,5 @@
use serde_json::json;
use crate::{
color::ColorU,
font_cache::FamilyId,
@ -6,8 +8,10 @@ use crate::{
rect::RectF,
vector::{vec2f, Vector2F},
},
json::{ToJson, Value},
text_layout::Line,
AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
AfterLayoutContext, DebugContext, Element, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
};
use std::{ops::Range, sync::Arc};
@ -152,4 +156,32 @@ impl Element for Label {
) -> bool {
false
}
fn debug(
&self,
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
) -> Value {
json!({
"type": "Label",
"font_size": self.font_size,
"bounds": bounds.to_json(),
"text": &self.text,
"family_id": ctx.font_cache.family_name(self.family_id).unwrap(),
"font_properties": self.font_properties.to_json(),
"highlights": self.highlights.to_json(),
})
}
}
impl ToJson for Highlights {
fn to_json(&self) -> Value {
json!({
"color": self.color.to_json(),
"indices": self.indices,
"font_properties": self.font_properties.to_json(),
})
}
}

View File

@ -1,9 +1,13 @@
use crate::{
font_cache::FamilyId,
fonts::Properties,
geometry::vector::{vec2f, Vector2F},
AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
},
json::{json, ToJson},
AfterLayoutContext, DebugContext, Element, ElementBox, Event, EventContext, LayoutContext,
PaintContext, SizeConstraint,
};
pub struct LineBox {
@ -85,4 +89,20 @@ impl Element for LineBox {
) -> bool {
self.child.dispatch_event(event, ctx)
}
fn debug(
&self,
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
) -> serde_json::Value {
json!({
"bounds": bounds.to_json(),
"family_id": ctx.font_cache.family_name(self.family_id).unwrap(),
"font_size": self.font_size,
"font_properties": self.font_properties.to_json(),
"child": self.child.debug(ctx),
})
}
}

View File

@ -1,6 +1,7 @@
use crate::{
geometry::{rect::RectF, vector::Vector2F},
AfterLayoutContext, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
json, AfterLayoutContext, DebugContext, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
};
use core::panic;
use replace_with::replace_with_or_abort;
@ -11,6 +12,7 @@ trait AnyElement {
fn after_layout(&mut self, _: &mut AfterLayoutContext) {}
fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext);
fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool;
fn debug(&self, ctx: &DebugContext) -> serde_json::Value;
fn size(&self) -> Vector2F;
fn metadata(&self) -> Option<&dyn Any>;
@ -53,6 +55,14 @@ pub trait Element {
None
}
fn debug(
&self,
bounds: RectF,
layout: &Self::LayoutState,
paint: &Self::PaintState,
ctx: &DebugContext,
) -> serde_json::Value;
fn boxed(self) -> ElementBox
where
Self: 'static + Sized,
@ -165,6 +175,18 @@ impl<T: Element> AnyElement for Lifecycle<T> {
| Lifecycle::PostPaint { element, .. } => element.metadata(),
}
}
fn debug(&self, ctx: &DebugContext) -> serde_json::Value {
match self {
Lifecycle::PostPaint {
element,
bounds,
layout,
paint,
} => element.debug(*bounds, layout, paint, ctx),
_ => panic!("invalid element lifecycle state"),
}
}
}
impl ElementBox {
@ -191,4 +213,8 @@ impl ElementBox {
pub fn metadata(&self) -> Option<&dyn Any> {
self.0.metadata()
}
pub fn debug(&self, ctx: &DebugContext) -> json::Value {
self.0.debug(ctx)
}
}

View File

@ -1,7 +1,8 @@
use crate::{
geometry::{rect::RectF, vector::Vector2F},
AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
json::{self, json, ToJson},
AfterLayoutContext, DebugContext, Element, ElementBox, Event, EventContext, LayoutContext,
PaintContext, SizeConstraint,
};
pub struct Stack {
@ -71,6 +72,20 @@ impl Element for Stack {
}
false
}
fn debug(
&self,
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
) -> json::Value {
json!({
"type": "Stack",
"bounds": bounds.to_json(),
"children": self.children.iter().map(|child| child.debug(ctx)).collect::<Vec<json::Value>>()
})
}
}
impl Extend<ElementBox> for Stack {

View File

@ -1,11 +1,13 @@
use serde_json::json;
use crate::{
color::ColorU,
geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
},
scene, AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
scene, AfterLayoutContext, DebugContext, Element, Event, EventContext, LayoutContext,
PaintContext, SizeConstraint,
};
pub struct Svg {
@ -86,8 +88,25 @@ impl Element for Svg {
) -> bool {
false
}
fn debug(
&self,
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
_: &DebugContext,
) -> serde_json::Value {
json!({
"type": "Svg",
"bounds": bounds.to_json(),
"path": self.path,
"color": self.color.to_json(),
})
}
}
use crate::json::ToJson;
fn from_usvg_rect(rect: usvg::Rect) -> RectF {
RectF::new(
vec2f(rect.x() as f32, rect.y() as f32),

View File

@ -7,8 +7,10 @@ use crate::{
rect::RectF,
vector::{vec2f, Vector2F},
},
json::{self, json},
ElementBox,
};
use json::ToJson;
use parking_lot::Mutex;
use std::{cmp, ops::Range, sync::Arc};
@ -236,4 +238,21 @@ where
handled
}
fn debug(
&self,
bounds: RectF,
layout: &Self::LayoutState,
_: &Self::PaintState,
ctx: &crate::DebugContext,
) -> json::Value {
json!({
"type": "UniformList",
"bounds": bounds.to_json(),
"scroll_max": layout.scroll_max,
"item_height": layout.item_height,
"items": layout.items.iter().map(|item| item.debug(ctx)).collect::<Vec<json::Value>>()
})
}
}

View File

@ -36,6 +36,15 @@ impl FontCache {
}))
}
pub fn family_name(&self, family_id: FamilyId) -> Result<String> {
self.0
.read()
.families
.get(family_id.0)
.ok_or_else(|| anyhow!("invalid family id"))
.map(|family| family.name.clone())
}
pub fn load_family(&self, names: &[&str]) -> Result<FamilyId> {
for name in names {
let state = self.0.upgradable_read();

View File

@ -1,7 +1,62 @@
use crate::json::json;
pub use font_kit::metrics::Metrics;
pub use font_kit::properties::{Properties, Weight};
pub use font_kit::properties::{Properties, Stretch, Style, Weight};
use crate::json::ToJson;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct FontId(pub usize);
pub type GlyphId = u32;
impl ToJson for Properties {
fn to_json(&self) -> crate::json::Value {
json!({
"style": self.style.to_json(),
"weight": self.weight.to_json(),
"stretch": self.stretch.to_json(),
})
}
}
impl ToJson for Style {
fn to_json(&self) -> crate::json::Value {
match self {
Style::Normal => json!("normal"),
Style::Italic => json!("italic"),
Style::Oblique => json!("oblique"),
}
}
}
impl ToJson for Weight {
fn to_json(&self) -> crate::json::Value {
if self.0 == Weight::THIN.0 {
json!("thin")
} else if self.0 == Weight::EXTRA_LIGHT.0 {
json!("extra light")
} else if self.0 == Weight::LIGHT.0 {
json!("light")
} else if self.0 == Weight::NORMAL.0 {
json!("normal")
} else if self.0 == Weight::MEDIUM.0 {
json!("medium")
} else if self.0 == Weight::SEMIBOLD.0 {
json!("semibold")
} else if self.0 == Weight::BOLD.0 {
json!("bold")
} else if self.0 == Weight::EXTRA_BOLD.0 {
json!("extra bold")
} else if self.0 == Weight::BLACK.0 {
json!("black")
} else {
json!(self.0)
}
}
}
impl ToJson for Stretch {
fn to_json(&self) -> serde_json::Value {
json!(self.0)
}
}

View File

@ -1,7 +1,8 @@
use super::scene::{Path, PathVertex};
use crate::color::ColorU;
use crate::{color::ColorU, json::ToJson};
pub use pathfinder_geometry::*;
use rect::RectF;
use serde_json::json;
use vector::{vec2f, Vector2F};
pub struct PathBuilder {
@ -106,3 +107,15 @@ impl PathBuilder {
}
}
}
impl ToJson for Vector2F {
fn to_json(&self) -> serde_json::Value {
json!([self.x(), self.y()])
}
}
impl ToJson for RectF {
fn to_json(&self) -> serde_json::Value {
json!({"origin": self.origin().to_json(), "size": self.size().to_json()})
}
}

15
gpui/src/json.rs Normal file
View File

@ -0,0 +1,15 @@
pub use serde_json::*;
pub trait ToJson {
fn to_json(&self) -> Value;
}
impl<T: ToJson> ToJson for Option<T> {
fn to_json(&self) -> Value {
if let Some(value) = self.as_ref() {
value.to_json()
} else {
json!(null)
}
}
}

View File

@ -18,11 +18,12 @@ mod util;
pub use elements::{Element, ElementBox};
pub mod executor;
pub use executor::Task;
pub mod color;
pub mod json;
pub mod keymap;
pub mod platform;
pub use pathfinder_color as color;
pub use platform::Event;
pub use presenter::{
AfterLayoutContext, Axis, EventContext, LayoutContext, PaintContext, SizeConstraint,
Vector2FExt,
AfterLayoutContext, Axis, DebugContext, EventContext, LayoutContext, PaintContext,
SizeConstraint, Vector2FExt,
};

View File

@ -2,11 +2,13 @@ use crate::{
app::{AppContext, MutableAppContext, WindowInvalidation},
elements::Element,
font_cache::FontCache,
json::ToJson,
platform::Event,
text_layout::TextLayoutCache,
AssetCache, ElementBox, Scene,
};
use pathfinder_geometry::vector::{vec2f, Vector2F};
use serde_json::json;
use std::{any::Any, collections::HashMap, sync::Arc};
pub struct Presenter {
@ -224,6 +226,12 @@ impl<'a> EventContext<'a> {
}
}
pub struct DebugContext<'a> {
rendered_views: &'a mut HashMap<usize, ElementBox>,
pub font_cache: &'a FontCache,
pub app: &'a AppContext,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Axis {
Horizontal,
@ -239,6 +247,15 @@ impl Axis {
}
}
impl ToJson for Axis {
fn to_json(&self) -> serde_json::Value {
match self {
Axis::Horizontal => json!("horizontal"),
Axis::Vertical => json!("vertical"),
}
}
}
pub trait Vector2FExt {
fn along(self, axis: Axis) -> f32;
}
@ -291,6 +308,15 @@ impl SizeConstraint {
}
}
impl ToJson for SizeConstraint {
fn to_json(&self) -> serde_json::Value {
json!({
"min": self.min.to_json(),
"max": self.max.to_json(),
})
}
}
pub struct ChildView {
view_id: usize,
}
@ -342,6 +368,25 @@ impl Element for ChildView {
) -> bool {
ctx.dispatch_event(self.view_id, event)
}
fn debug(
&self,
bounds: pathfinder_geometry::rect::RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
ctx: &DebugContext,
) -> serde_json::Value {
json!({
"type": "ChildView",
"view_id": self.view_id,
"bounds": bounds.to_json(),
"child": if let Some(view) = ctx.rendered_views.get(&self.view_id) {
view.debug(ctx)
} else {
json!(null)
}
})
}
}
#[cfg(test)]

View File

@ -1,7 +1,10 @@
use serde_json::json;
use crate::{
color::ColorU,
fonts::{FontId, GlyphId},
geometry::{rect::RectF, vector::Vector2F},
json::ToJson,
};
pub struct Scene {
@ -258,3 +261,22 @@ impl Border {
}
}
}
impl ToJson for Border {
fn to_json(&self) -> serde_json::Value {
let mut value = json!({});
if self.top {
value["top"] = json!(self.width);
}
if self.right {
value["right"] = json!(self.width);
}
if self.bottom {
value["bottom"] = json!(self.width);
}
if self.left {
value["left"] = json!(self.width);
}
value
}
}

View File

@ -6,10 +6,12 @@ use gpui::{
vector::{vec2f, Vector2F},
PathBuilder,
},
json::{self, ToJson},
text_layout::{self, TextLayoutCache},
AfterLayoutContext, AppContext, Border, Element, Event, EventContext, FontCache, LayoutContext,
PaintContext, Quad, Scene, SizeConstraint, ViewHandle,
};
use json::json;
use smallvec::SmallVec;
use std::cmp::Ordering;
use std::{
@ -477,6 +479,19 @@ impl Element for BufferElement {
false
}
}
fn debug(
&self,
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
_: &gpui::DebugContext,
) -> json::Value {
json!({
"type": "BufferElement",
"bounds": bounds.to_json()
})
}
}
pub struct LayoutState {