Add tags to `UiStack` (#4617)
You can now set custom tags on the `UiStack`. This allows you to write code that is situationally aware at runtime. For instance, you could decide wether or not a label should truncate its text depending on what part of your ui it is in, without having to pass that info down via the callstack.
This commit is contained in:
parent
321d2441c1
commit
bb8400853f
|
|
@ -253,10 +253,7 @@ impl Frame {
|
||||||
let content_ui = ui.child_ui(
|
let content_ui = ui.child_ui(
|
||||||
inner_rect,
|
inner_rect,
|
||||||
*ui.layout(),
|
*ui.layout(),
|
||||||
Some(UiStackInfo {
|
Some(UiStackInfo::new(UiKind::Frame).with_frame(self)),
|
||||||
frame: self,
|
|
||||||
kind: Some(UiKind::Frame),
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// content_ui.set_clip_rect(outer_rect_bounds.shrink(self.stroke.width * 0.5)); // Can't do this since we don't know final size yet
|
// content_ui.set_clip_rect(outer_rect_bounds.shrink(self.stroke.width * 0.5)); // Can't do this since we don't know final size yet
|
||||||
|
|
|
||||||
|
|
@ -362,10 +362,7 @@ impl SidePanel {
|
||||||
self.id,
|
self.id,
|
||||||
available_rect,
|
available_rect,
|
||||||
clip_rect,
|
clip_rect,
|
||||||
UiStackInfo {
|
UiStackInfo::default(),
|
||||||
kind: None, // set by show_inside_dyn
|
|
||||||
frame: Frame::default(),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents);
|
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents);
|
||||||
|
|
@ -848,10 +845,7 @@ impl TopBottomPanel {
|
||||||
self.id,
|
self.id,
|
||||||
available_rect,
|
available_rect,
|
||||||
clip_rect,
|
clip_rect,
|
||||||
UiStackInfo {
|
UiStackInfo::default(), // set by show_inside_dyn
|
||||||
kind: None, // set by show_inside_dyn
|
|
||||||
frame: Frame::default(),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents);
|
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents);
|
||||||
|
|
@ -1120,10 +1114,7 @@ impl CentralPanel {
|
||||||
id,
|
id,
|
||||||
available_rect,
|
available_rect,
|
||||||
clip_rect,
|
clip_rect,
|
||||||
UiStackInfo {
|
UiStackInfo::default(), // set by show_inside_dyn
|
||||||
kind: None, // set by show_inside_dyn
|
|
||||||
frame: Frame::default(),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents);
|
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents);
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,7 @@ impl Ui {
|
||||||
let ui_stack = UiStack {
|
let ui_stack = UiStack {
|
||||||
id,
|
id,
|
||||||
layout_direction: layout.main_dir,
|
layout_direction: layout.main_dir,
|
||||||
kind: ui_stack_info.kind,
|
info: ui_stack_info,
|
||||||
frame: ui_stack_info.frame,
|
|
||||||
parent: None,
|
parent: None,
|
||||||
min_rect: placer.min_rect(),
|
min_rect: placer.min_rect(),
|
||||||
max_rect: placer.max_rect(),
|
max_rect: placer.max_rect(),
|
||||||
|
|
@ -130,6 +129,8 @@ impl Ui {
|
||||||
///
|
///
|
||||||
/// Note: calling this function twice from the same [`Ui`] will create a conflict of id. Use
|
/// Note: calling this function twice from the same [`Ui`] will create a conflict of id. Use
|
||||||
/// [`Self::scope`] if needed.
|
/// [`Self::scope`] if needed.
|
||||||
|
///
|
||||||
|
/// When in doubt, use `None` for the `UiStackInfo` argument.
|
||||||
pub fn child_ui(
|
pub fn child_ui(
|
||||||
&mut self,
|
&mut self,
|
||||||
max_rect: Rect,
|
max_rect: Rect,
|
||||||
|
|
@ -140,6 +141,8 @@ impl Ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`Ui`] at a specific region with a specific id.
|
/// Create a new [`Ui`] at a specific region with a specific id.
|
||||||
|
///
|
||||||
|
/// When in doubt, use `None` for the `UiStackInfo` argument.
|
||||||
pub fn child_ui_with_id_source(
|
pub fn child_ui_with_id_source(
|
||||||
&mut self,
|
&mut self,
|
||||||
max_rect: Rect,
|
max_rect: Rect,
|
||||||
|
|
@ -162,12 +165,10 @@ impl Ui {
|
||||||
|
|
||||||
let new_id = self.id.with(id_source);
|
let new_id = self.id.with(id_source);
|
||||||
let placer = Placer::new(max_rect, layout);
|
let placer = Placer::new(max_rect, layout);
|
||||||
let ui_stack_info = ui_stack_info.unwrap_or_default();
|
|
||||||
let ui_stack = UiStack {
|
let ui_stack = UiStack {
|
||||||
id: new_id,
|
id: new_id,
|
||||||
layout_direction: layout.main_dir,
|
layout_direction: layout.main_dir,
|
||||||
kind: ui_stack_info.kind,
|
info: ui_stack_info.unwrap_or_default(),
|
||||||
frame: ui_stack_info.frame,
|
|
||||||
parent: Some(self.stack.clone()),
|
parent: Some(self.stack.clone()),
|
||||||
min_rect: placer.min_rect(),
|
min_rect: placer.min_rect(),
|
||||||
max_rect: placer.max_rect(),
|
max_rect: placer.max_rect(),
|
||||||
|
|
@ -1956,7 +1957,22 @@ impl Ui {
|
||||||
id_source: impl Hash,
|
id_source: impl Hash,
|
||||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||||
) -> InnerResponse<R> {
|
) -> InnerResponse<R> {
|
||||||
self.scope_dyn(Box::new(add_contents), Id::new(id_source))
|
self.scope_dyn(Box::new(add_contents), Id::new(id_source), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Push another level onto the [`UiStack`].
|
||||||
|
///
|
||||||
|
/// You can use this, for instance, to tag a group of widgets.
|
||||||
|
pub fn push_stack_info<R>(
|
||||||
|
&mut self,
|
||||||
|
ui_stack_info: UiStackInfo,
|
||||||
|
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||||
|
) -> InnerResponse<R> {
|
||||||
|
self.scope_dyn(
|
||||||
|
Box::new(add_contents),
|
||||||
|
Id::new("child"),
|
||||||
|
Some(ui_stack_info),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a scoped child ui.
|
/// Create a scoped child ui.
|
||||||
|
|
@ -1972,18 +1988,19 @@ impl Ui {
|
||||||
/// # });
|
/// # });
|
||||||
/// ```
|
/// ```
|
||||||
pub fn scope<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
|
pub fn scope<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
|
||||||
self.scope_dyn(Box::new(add_contents), Id::new("child"))
|
self.scope_dyn(Box::new(add_contents), Id::new("child"), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scope_dyn<'c, R>(
|
fn scope_dyn<'c, R>(
|
||||||
&mut self,
|
&mut self,
|
||||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||||
id_source: Id,
|
id_source: Id,
|
||||||
|
ui_stack_info: Option<UiStackInfo>,
|
||||||
) -> InnerResponse<R> {
|
) -> InnerResponse<R> {
|
||||||
let child_rect = self.available_rect_before_wrap();
|
let child_rect = self.available_rect_before_wrap();
|
||||||
let next_auto_id_source = self.next_auto_id_source;
|
let next_auto_id_source = self.next_auto_id_source;
|
||||||
let mut child_ui =
|
let mut child_ui =
|
||||||
self.child_ui_with_id_source(child_rect, *self.layout(), id_source, None);
|
self.child_ui_with_id_source(child_rect, *self.layout(), id_source, ui_stack_info);
|
||||||
self.next_auto_id_source = next_auto_id_source; // HACK: we want `scope` to only increment this once, so that `ui.scope` is equivalent to `ui.allocate_space`.
|
self.next_auto_id_source = next_auto_id_source; // HACK: we want `scope` to only increment this once, so that `ui.scope` is equivalent to `ui.allocate_space`.
|
||||||
let ret = add_contents(&mut child_ui);
|
let ret = add_contents(&mut child_ui);
|
||||||
let response = self.allocate_rect(child_ui.min_rect(), Sense::hover());
|
let response = self.allocate_rect(child_ui.min_rect(), Sense::hover());
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use std::iter::FusedIterator;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::{any::Any, iter::FusedIterator};
|
||||||
|
|
||||||
use crate::{Direction, Frame, Id, Rect};
|
use crate::{Direction, Frame, Id, Rect};
|
||||||
|
|
||||||
|
|
@ -54,6 +54,7 @@ pub enum UiKind {
|
||||||
|
|
||||||
impl UiKind {
|
impl UiKind {
|
||||||
/// Is this any kind of panel?
|
/// Is this any kind of panel?
|
||||||
|
#[inline]
|
||||||
pub fn is_panel(&self) -> bool {
|
pub fn is_panel(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
|
|
@ -64,25 +65,121 @@ impl UiKind {
|
||||||
| Self::BottomPanel
|
| Self::BottomPanel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this any kind of [`crate::Area`]?
|
||||||
|
#[inline]
|
||||||
|
pub fn is_area(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::CentralPanel
|
||||||
|
| Self::LeftPanel
|
||||||
|
| Self::RightPanel
|
||||||
|
| Self::TopPanel
|
||||||
|
| Self::BottomPanel
|
||||||
|
| Self::Frame
|
||||||
|
| Self::ScrollArea
|
||||||
|
| Self::Resize
|
||||||
|
| Self::TableCell => false,
|
||||||
|
|
||||||
|
Self::Window
|
||||||
|
| Self::Menu
|
||||||
|
| Self::Popup
|
||||||
|
| Self::Tooltip
|
||||||
|
| Self::Picker
|
||||||
|
| Self::GenericArea => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Information about a [`crate::Ui`] to be included in the corresponding [`UiStack`].
|
/// Information about a [`crate::Ui`] to be included in the corresponding [`UiStack`].
|
||||||
#[derive(Default, Copy, Clone, Debug)]
|
#[derive(Clone, Default, Debug)]
|
||||||
pub struct UiStackInfo {
|
pub struct UiStackInfo {
|
||||||
pub kind: Option<UiKind>,
|
pub kind: Option<UiKind>,
|
||||||
pub frame: Frame,
|
pub frame: Frame,
|
||||||
|
pub tags: UiTags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiStackInfo {
|
impl UiStackInfo {
|
||||||
/// Create a new [`UiStackInfo`] with the given kind and an empty frame.
|
/// Create a new [`UiStackInfo`] with the given kind and an empty frame.
|
||||||
|
#[inline]
|
||||||
pub fn new(kind: UiKind) -> Self {
|
pub fn new(kind: UiKind) -> Self {
|
||||||
Self {
|
Self {
|
||||||
kind: Some(kind),
|
kind: Some(kind),
|
||||||
frame: Default::default(),
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_frame(mut self, frame: Frame) -> Self {
|
||||||
|
self.frame = frame;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert a tag with no value.
|
||||||
|
#[inline]
|
||||||
|
pub fn with_tag(mut self, key: impl Into<String>) -> Self {
|
||||||
|
self.tags.insert(key, None);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert a tag with some value.
|
||||||
|
#[inline]
|
||||||
|
pub fn with_tag_value(
|
||||||
|
mut self,
|
||||||
|
key: impl Into<String>,
|
||||||
|
value: impl Any + Send + Sync + 'static,
|
||||||
|
) -> Self {
|
||||||
|
self.tags.insert(key, Some(Arc::new(value)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// User-chosen tags.
|
||||||
|
///
|
||||||
|
/// You can use this in any way you want,
|
||||||
|
/// i.e. to set some tag on a [`crate::Ui`] and then in your own widget check
|
||||||
|
/// for the existence of this tag up the [`UiStack`].
|
||||||
|
///
|
||||||
|
/// Note that egui never sets any tags itself, so this is purely for user code.
|
||||||
|
///
|
||||||
|
/// All tagging is transient, and will only live as long as the parent [`crate::Ui`], i.e. within a single render frame.
|
||||||
|
#[derive(Clone, Default, Debug)]
|
||||||
|
pub struct UiTags(pub ahash::HashMap<String, Option<Arc<dyn Any + Send + Sync + 'static>>>);
|
||||||
|
|
||||||
|
impl UiTags {
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(
|
||||||
|
&mut self,
|
||||||
|
key: impl Into<String>,
|
||||||
|
value: Option<Arc<dyn Any + Send + Sync + 'static>>,
|
||||||
|
) {
|
||||||
|
self.0.insert(key.into(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn contains(&self, key: &str) -> bool {
|
||||||
|
self.0.contains_key(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of a tag.
|
||||||
|
///
|
||||||
|
/// Note that `None` is returned both if the key is set to the value `None`,
|
||||||
|
/// and if the key is not set at all.
|
||||||
|
#[inline]
|
||||||
|
pub fn get_any(&self, key: &str) -> Option<&Arc<dyn Any + Send + Sync + 'static>> {
|
||||||
|
self.0.get(key)?.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of a tag.
|
||||||
|
///
|
||||||
|
/// Note that `None` is returned both if the key is set to the value `None`,
|
||||||
|
/// and if the key is not set at all.
|
||||||
|
pub fn get_downcast<T: Any + Send + Sync + 'static>(&self, key: &str) -> Option<&T> {
|
||||||
|
self.0.get(key)?.as_ref().and_then(|any| any.downcast_ref())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
@ -96,12 +193,11 @@ impl UiStackInfo {
|
||||||
/// Note: since [`UiStack`] contains a reference to its parent, it is both a stack, and a node within
|
/// Note: since [`UiStack`] contains a reference to its parent, it is both a stack, and a node within
|
||||||
/// that stack. Most of its methods are about the specific node, but some methods walk up the
|
/// that stack. Most of its methods are about the specific node, but some methods walk up the
|
||||||
/// hierarchy to provide information about the entire stack.
|
/// hierarchy to provide information about the entire stack.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UiStack {
|
pub struct UiStack {
|
||||||
// stuff that `Ui::child_ui` can deal with directly
|
// stuff that `Ui::child_ui` can deal with directly
|
||||||
pub id: Id,
|
pub id: Id,
|
||||||
pub kind: Option<UiKind>,
|
pub info: UiStackInfo,
|
||||||
pub frame: Frame,
|
|
||||||
pub layout_direction: Direction,
|
pub layout_direction: Direction,
|
||||||
pub min_rect: Rect,
|
pub min_rect: Rect,
|
||||||
pub max_rect: Rect,
|
pub max_rect: Rect,
|
||||||
|
|
@ -110,10 +206,26 @@ pub struct UiStack {
|
||||||
|
|
||||||
// these methods act on this specific node
|
// these methods act on this specific node
|
||||||
impl UiStack {
|
impl UiStack {
|
||||||
|
#[inline]
|
||||||
|
pub fn kind(&self) -> Option<UiKind> {
|
||||||
|
self.info.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn frame(&self) -> &Frame {
|
||||||
|
&self.info.frame
|
||||||
|
}
|
||||||
|
|
||||||
|
/// User tags.
|
||||||
|
#[inline]
|
||||||
|
pub fn tags(&self) -> &UiTags {
|
||||||
|
&self.info.tags
|
||||||
|
}
|
||||||
|
|
||||||
/// Is this [`crate::Ui`] a panel?
|
/// Is this [`crate::Ui`] a panel?
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_panel_ui(&self) -> bool {
|
pub fn is_panel_ui(&self) -> bool {
|
||||||
self.kind.map_or(false, |kind| kind.is_panel())
|
self.kind().map_or(false, |kind| kind.is_panel())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this a root [`crate::Ui`], i.e. created with [`crate::Ui::new()`]?
|
/// Is this a root [`crate::Ui`], i.e. created with [`crate::Ui::new()`]?
|
||||||
|
|
@ -125,7 +237,7 @@ impl UiStack {
|
||||||
/// This this [`crate::Ui`] a [`crate::Frame`] with a visible stroke?
|
/// This this [`crate::Ui`] a [`crate::Frame`] with a visible stroke?
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn has_visible_frame(&self) -> bool {
|
pub fn has_visible_frame(&self) -> bool {
|
||||||
!self.frame.stroke.is_empty()
|
!self.info.frame.stroke.is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,7 +251,7 @@ impl UiStack {
|
||||||
|
|
||||||
/// Check if this node is or is contained in a [`crate::Ui`] of a specific kind.
|
/// Check if this node is or is contained in a [`crate::Ui`] of a specific kind.
|
||||||
pub fn contained_in(&self, kind: UiKind) -> bool {
|
pub fn contained_in(&self, kind: UiKind) -> bool {
|
||||||
self.iter().any(|frame| frame.kind == Some(kind))
|
self.iter().any(|frame| frame.kind() == Some(kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -547,7 +547,7 @@ fn ui_stack_demo(ui: &mut Ui) {
|
||||||
});
|
});
|
||||||
|
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(if let Some(kind) = node.kind {
|
ui.label(if let Some(kind) = node.kind() {
|
||||||
format!("{kind:?}")
|
format!("{kind:?}")
|
||||||
} else {
|
} else {
|
||||||
"-".to_owned()
|
"-".to_owned()
|
||||||
|
|
|
||||||
|
|
@ -209,9 +209,9 @@ fn full_span_horizontal_range(ui_stack: &egui::UiStack) -> Rangef {
|
||||||
if node.has_visible_frame()
|
if node.has_visible_frame()
|
||||||
|| node.is_panel_ui()
|
|| node.is_panel_ui()
|
||||||
|| node.is_root_ui()
|
|| node.is_root_ui()
|
||||||
|| node.kind == Some(UiKind::TableCell)
|
|| node.kind() == Some(UiKind::TableCell)
|
||||||
{
|
{
|
||||||
return (node.max_rect + node.frame.inner_margin).x_range();
|
return (node.max_rect + node.frame().inner_margin).x_range();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,7 +280,7 @@ fn stack_ui_impl(ui: &mut egui::Ui, stack: &egui::UiStack) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
let s = if let Some(kind) = node.kind {
|
let s = if let Some(kind) = node.kind() {
|
||||||
format!("{kind:?}")
|
format!("{kind:?}")
|
||||||
} else {
|
} else {
|
||||||
"-".to_owned()
|
"-".to_owned()
|
||||||
|
|
@ -289,7 +289,8 @@ fn stack_ui_impl(ui: &mut egui::Ui, stack: &egui::UiStack) {
|
||||||
ui.label(s);
|
ui.label(s);
|
||||||
});
|
});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
if node.frame.stroke == egui::Stroke::NONE {
|
let frame = node.frame();
|
||||||
|
if frame.stroke == egui::Stroke::NONE {
|
||||||
ui.label("-");
|
ui.label("-");
|
||||||
} else {
|
} else {
|
||||||
let mut layout_job = egui::text::LayoutJob::default();
|
let mut layout_job = egui::text::LayoutJob::default();
|
||||||
|
|
@ -298,11 +299,11 @@ fn stack_ui_impl(ui: &mut egui::Ui, stack: &egui::UiStack) {
|
||||||
0.0,
|
0.0,
|
||||||
egui::TextFormat::simple(
|
egui::TextFormat::simple(
|
||||||
egui::TextStyle::Body.resolve(ui.style()),
|
egui::TextStyle::Body.resolve(ui.style()),
|
||||||
node.frame.stroke.color,
|
frame.stroke.color,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
layout_job.append(
|
layout_job.append(
|
||||||
format!("{}px", node.frame.stroke.width).as_str(),
|
format!("{}px", frame.stroke.width).as_str(),
|
||||||
0.0,
|
0.0,
|
||||||
egui::TextFormat::simple(
|
egui::TextFormat::simple(
|
||||||
egui::TextStyle::Body.resolve(ui.style()),
|
egui::TextStyle::Body.resolve(ui.style()),
|
||||||
|
|
@ -314,10 +315,10 @@ fn stack_ui_impl(ui: &mut egui::Ui, stack: &egui::UiStack) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(print_margin(&node.frame.inner_margin));
|
ui.label(print_margin(&node.frame().inner_margin));
|
||||||
});
|
});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(print_margin(&node.frame.outer_margin));
|
ui.label(print_margin(&node.frame().outer_margin));
|
||||||
});
|
});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(format!("{:?}", node.layout_direction));
|
ui.label(format!("{:?}", node.layout_direction));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue