Direction enum now one of LeftToRight, RightToLeft, TopDown, BottomUp

This commit is contained in:
Emil Ernerfeldt 2020-12-06 12:47:45 +01:00
parent ed6739867d
commit c520f2e9cc
9 changed files with 249 additions and 238 deletions

View file

@ -16,6 +16,21 @@ pub enum Align {
Max, Max,
} }
impl Align {
pub fn left() -> Self {
Self::Min
}
pub fn right() -> Self {
Self::Max
}
pub fn top() -> Self {
Self::Min
}
pub fn bottom() -> Self {
Self::Max
}
}
impl Default for Align { impl Default for Align {
fn default() -> Align { fn default() -> Align {
Align::Min Align::Min

View file

@ -1,7 +1,6 @@
use std::hash::Hash; use std::hash::Hash;
use crate::{ use crate::{
layout::Direction,
paint::{PaintCmd, TextStyle}, paint::{PaintCmd, TextStyle},
widgets::Label, widgets::Label,
*, *,
@ -168,7 +167,7 @@ struct Prepared {
impl CollapsingHeader { impl CollapsingHeader {
fn begin(self, ui: &mut Ui) -> Prepared { fn begin(self, ui: &mut Ui) -> Prepared {
assert!( assert!(
ui.layout().dir() == Direction::Vertical, ui.layout().main_dir().is_vertical(),
"Horizontal collapsing is unimplemented" "Horizontal collapsing is unimplemented"
); );
let Self { let Self {

View file

@ -60,10 +60,13 @@ pub fn combo_box(
let frame = Frame::popup(ui.style()); let frame = Frame::popup(ui.style());
let frame_margin = frame.margin; let frame_margin = frame.margin;
frame.show(ui, |ui| { frame.show(ui, |ui| {
ui.with_layout(Layout::justified(Direction::Vertical), |ui| { ui.with_layout(
ui.set_min_width(button_response.rect.width() - 2.0 * frame_margin.x); Layout::top_down(Align::left()).with_cross_justify(true),
menu_contents(ui); |ui| {
}); ui.set_min_width(button_response.rect.width() - 2.0 * frame_margin.x);
menu_contents(ui);
},
);
}) })
}); });

View file

@ -44,7 +44,7 @@ impl DemoWindow {
}); });
CollapsingHeader::new("Layout") CollapsingHeader::new("Layout")
.default_open(false) .default_open(true)
.show(ui, |ui| self.layout.ui(ui)); .show(ui, |ui| self.layout.ui(ui));
CollapsingHeader::new("Tree") CollapsingHeader::new("Tree")
@ -304,29 +304,25 @@ use crate::layout::*;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))] #[cfg_attr(feature = "serde", serde(default))]
struct LayoutDemo { struct LayoutDemo {
dir: Direction, // Identical to contents of `egui::Layout`
align: Option<Align>, // None == justified main_dir: Direction,
reversed: bool, cross_align: Align,
cross_justify: bool,
} }
impl Default for LayoutDemo { impl Default for LayoutDemo {
fn default() -> Self { fn default() -> Self {
Self { Self {
dir: Direction::Vertical, main_dir: Direction::TopDown,
align: Some(Align::Center), cross_align: Align::Min,
reversed: false, cross_justify: false,
} }
} }
} }
impl LayoutDemo { impl LayoutDemo {
fn layout(&self) -> Layout { fn layout(&self) -> Layout {
let layout = Layout::from_dir_align(self.dir, self.align); Layout::from_parts(self.main_dir, self.cross_align, self.cross_justify)
if self.reversed {
layout.reverse()
} else {
layout
}
} }
pub fn ui(&mut self, ui: &mut Ui) { pub fn ui(&mut self, ui: &mut Ui) {
@ -347,39 +343,24 @@ impl LayoutDemo {
// TODO: enum iter // TODO: enum iter
for &dir in &[Direction::Horizontal, Direction::Vertical] { for &dir in &[
if ui Direction::LeftToRight,
.add(RadioButton::new(self.dir == dir, format!("{:?}", dir))) Direction::RightToLeft,
.clicked Direction::TopDown,
{ Direction::BottomUp,
self.dir = dir; ] {
} ui.radio_value(&mut self.main_dir, dir, format!("{:?}", dir));
} }
ui.checkbox(&mut self.reversed, "Reversed");
ui.separator(); ui.separator();
ui.label("Align:"); ui.label("Align:");
for &align in &[Align::Min, Align::Center, Align::Max] { for &align in &[Align::Min, Align::Center, Align::Max] {
if ui ui.radio_value(&mut self.cross_align, align, format!("{:?}", align));
.add(RadioButton::new(
self.align == Some(align),
format!("{:?}", align),
))
.clicked
{
self.align = Some(align);
}
}
if ui
.add(RadioButton::new(self.align == None, "Justified"))
.on_hover_text("Try to fill full width/height (e.g. buttons)")
.clicked
{
self.align = None;
} }
ui.checkbox(&mut self.cross_justify, "Justified")
.on_hover_text("Try to fill full width/height (e.g. buttons)");
} }
} }

View file

@ -345,7 +345,7 @@ fn show_menu_bar(ui: &mut Ui, windows: &mut OpenWindows, seconds_since_midnight:
(time % 1.0 * 100.0).floor() (time % 1.0 * 100.0).floor()
); );
ui.with_layout(Layout::horizontal(Align::Center).reverse(), |ui| { ui.with_layout(Layout::right_to_left(), |ui| {
if ui if ui
.add(Button::new(time).text_style(TextStyle::Monospace)) .add(Button::new(time).text_style(TextStyle::Monospace))
.clicked .clicked

View file

@ -64,18 +64,30 @@ impl Region {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/// `Layout` direction (horizontal or vertical). /// Main layout direction
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum Direction { pub enum Direction {
Horizontal, LeftToRight,
Vertical, RightToLeft,
TopDown,
BottomUp,
} }
impl Default for Direction { impl Direction {
fn default() -> Direction { pub fn is_horizontal(self) -> bool {
Direction::Vertical match self {
Direction::LeftToRight | Direction::RightToLeft => true,
Direction::TopDown | Direction::BottomUp => false,
}
}
pub fn is_vertical(self) -> bool {
match self {
Direction::LeftToRight | Direction::RightToLeft => false,
Direction::TopDown | Direction::BottomUp => true,
}
} }
} }
@ -85,111 +97,133 @@ impl Default for Direction {
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
// #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] // #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Layout { pub struct Layout {
/// Lay out things horizontally or vertically? Main axis. /// Main axis direction
dir: Direction, main_dir: Direction,
/// How to align things on the cross axis. /// How to align things on the cross axis.
/// For vertical layouts: put things to left, center or right? /// For vertical layouts: put things to left, center or right?
/// For horizontal layouts: put things to top, center or bottom? /// For horizontal layouts: put things to top, center or bottom?
/// `None` means justified, which means full width (vertical layout) or height (horizontal layouts). cross_align: Align,
align: Option<Align>,
/// Lay out things in reversed order, i.e. from the right or bottom-up. /// Justify the cross axis?
reversed: bool, /// For vertical layouts justify mean all widgets get maximum width.
/// For horizontal layouts justify mean all widgets get maximum height.
cross_justify: bool,
} }
impl Default for Layout { impl Default for Layout {
fn default() -> Self { fn default() -> Self {
// TODO: Get from `Style` instead.
// This is a very euro-centric default.
Self { Self {
dir: Direction::Vertical, main_dir: Direction::TopDown,
align: Some(Align::Min), cross_align: Align::left(),
reversed: false, cross_justify: false,
} }
} }
} }
impl Layout { impl Layout {
/// None align means justified, e.g. fill full width/height. /// None align means justified, e.g. fill full width/height.
pub fn from_dir_align(dir: Direction, align: Option<Align>) -> Self { pub(crate) fn from_parts(main_dir: Direction, cross_align: Align, cross_justify: bool) -> Self {
Self { Self {
dir, main_dir,
align, cross_align,
reversed: false, cross_justify,
} }
} }
pub fn vertical(align: Align) -> Self { #[deprecated = "Use `top_down`"]
pub fn vertical(cross_align: Align) -> Self {
Self::top_down(cross_align)
}
#[deprecated = "Use `left_to_right`"]
pub fn horizontal(cross_align: Align) -> Self {
Self::left_to_right().with_cross_align(cross_align)
}
pub fn left_to_right() -> Self {
Self { Self {
dir: Direction::Vertical, main_dir: Direction::LeftToRight,
align: Some(align), cross_align: Align::Center,
reversed: false, cross_justify: false,
} }
} }
pub fn horizontal(align: Align) -> Self { pub fn right_to_left() -> Self {
Self { Self {
dir: Direction::Horizontal, main_dir: Direction::RightToLeft,
align: Some(align), cross_align: Align::Center,
reversed: false, cross_justify: false,
} }
} }
/// Full-width layout. pub fn top_down(cross_align: Align) -> Self {
/// Nice for menus etc where each button is full width.
pub fn justified(dir: Direction) -> Self {
Self { Self {
dir, main_dir: Direction::TopDown,
align: None, cross_align,
reversed: false, cross_justify: false,
} }
} }
#[must_use] pub fn bottom_up(cross_align: Align) -> Self {
pub fn reverse(self) -> Self {
Self { Self {
dir: self.dir, main_dir: Direction::BottomUp,
align: self.align, cross_align,
reversed: !self.reversed, cross_justify: false,
} }
} }
#[must_use] pub fn with_cross_align(self, cross_align: Align) -> Self {
pub fn with_reversed(self, reversed: bool) -> Self { Self {
if reversed { cross_align,
self.reverse() ..self
} else {
self
} }
} }
pub fn dir(self) -> Direction { pub fn with_cross_justify(self, cross_justify: bool) -> Self {
self.dir Self {
cross_justify,
..self
}
} }
pub fn align(self) -> Option<Align> { // ------------------------------------------------------------------------
self.align
pub fn main_dir(self) -> Direction {
self.main_dir
} }
pub fn is_reversed(self) -> bool { pub fn cross_align(self) -> Align {
self.reversed self.cross_align
} }
pub fn cross_justify(self) -> bool {
self.cross_justify
}
pub fn is_horizontal(self) -> bool {
self.main_dir().is_horizontal()
}
pub fn is_vertical(self) -> bool {
self.main_dir().is_vertical()
}
pub fn prefer_right_to_left(self) -> bool {
self.main_dir == Direction::RightToLeft
|| self.main_dir.is_vertical() && self.cross_align == Align::Max
}
// ------------------------------------------------------------------------
fn initial_cursor(self, max_rect: Rect) -> Pos2 { fn initial_cursor(self, max_rect: Rect) -> Pos2 {
match self.dir { match self.main_dir {
Direction::Horizontal => { Direction::LeftToRight => max_rect.left_top(),
if self.reversed { Direction::RightToLeft => max_rect.right_top(),
max_rect.right_top() Direction::TopDown => max_rect.left_top(),
} else { Direction::BottomUp => max_rect.left_bottom(),
max_rect.left_top()
}
}
Direction::Vertical => {
if self.reversed {
max_rect.left_bottom()
} else {
max_rect.left_top()
}
}
} }
} }
@ -215,52 +249,45 @@ impl Layout {
/// for the next widget? /// for the next widget?
fn available_from_cursor_max_rect(self, cursor: Pos2, max_rect: Rect) -> Rect { fn available_from_cursor_max_rect(self, cursor: Pos2, max_rect: Rect) -> Rect {
let mut rect = max_rect; let mut rect = max_rect;
match self.dir {
Direction::Horizontal => { match self.main_dir {
rect.min.y = cursor.y; Direction::LeftToRight => {
if self.reversed {
rect.max.x = cursor.x;
} else {
rect.min.x = cursor.x;
}
}
Direction::Vertical => {
rect.min.x = cursor.x; rect.min.x = cursor.x;
if self.reversed { rect.min.y = cursor.y;
rect.max.y = cursor.y; }
} else { Direction::RightToLeft => {
rect.min.y = cursor.y; rect.max.x = cursor.x;
} rect.min.y = cursor.y;
}
Direction::TopDown => {
rect.min.x = cursor.x;
rect.min.y = cursor.y;
}
Direction::BottomUp => {
rect.min.x = cursor.x;
rect.max.y = cursor.y;
} }
} }
rect rect
} }
/// Advance the cursor by this many points. /// Advance the cursor by this many points.
pub fn advance_cursor(self, region: &mut Region, amount: f32) { pub fn advance_cursor(self, region: &mut Region, amount: f32) {
match self.dir() { match self.main_dir {
Direction::Horizontal => { Direction::LeftToRight => region.cursor.x += amount,
if self.is_reversed() { Direction::RightToLeft => region.cursor.x -= amount,
region.cursor.x -= amount; Direction::TopDown => region.cursor.y += amount,
} else { Direction::BottomUp => region.cursor.y -= amount,
region.cursor.x += amount;
}
}
Direction::Vertical => {
if self.is_reversed() {
region.cursor.y -= amount;
} else {
region.cursor.y += amount;
}
}
} }
} }
/// Advance the cursor by this spacing /// Advance the cursor by this spacing
pub fn advance_cursor2(self, region: &mut Region, amount: Vec2) { pub fn advance_cursor2(self, region: &mut Region, amount: Vec2) {
match self.dir() { if self.main_dir.is_horizontal() {
Direction::Horizontal => self.advance_cursor(region, amount.x), self.advance_cursor(region, amount.x)
Direction::Vertical => self.advance_cursor(region, amount.y), } else {
self.advance_cursor(region, amount.y)
} }
} }
@ -282,49 +309,39 @@ impl Layout {
let mut child_size = minimum_child_size; let mut child_size = minimum_child_size;
let mut child_move = Vec2::default(); let mut child_move = Vec2::default();
let mut cursor_change = Vec2::default();
match self.dir { if self.main_dir.is_horizontal() {
Direction::Horizontal => { if self.cross_justify {
if let Some(align) = self.align { // fill full height
child_move.y += match align { child_size.y = child_size.y.max(available_size.y);
Align::Min => 0.0, } else {
Align::Center => 0.5 * (available_size.y - child_size.y), child_move.y += match self.cross_align {
Align::Max => available_size.y - child_size.y, Align::Min => 0.0,
}; Align::Center => 0.5 * (available_size.y - child_size.y),
} else { Align::Max => available_size.y - child_size.y,
// justified: fill full height };
child_size.y = child_size.y.max(available_size.y); }
} } else {
if self.cross_justify {
cursor_change.x += child_size.x; // justified: fill full width
} child_size.x = child_size.x.max(available_size.x);
Direction::Vertical => { } else {
if let Some(align) = self.align { child_move.x += match self.cross_align {
child_move.x += match align { Align::Min => 0.0,
Align::Min => 0.0, Align::Center => 0.5 * (available_size.x - child_size.x),
Align::Center => 0.5 * (available_size.x - child_size.x), Align::Max => available_size.x - child_size.x,
Align::Max => available_size.x - child_size.x,
};
} else {
// justified: fill full width
child_size.x = child_size.x.max(available_size.x);
}; };
cursor_change.y += child_size.y;
} }
} }
if self.is_reversed() { let child_pos = match self.main_dir {
let child_pos = region.cursor + child_move; Direction::LeftToRight => region.cursor + child_move,
let child_pos = match self.dir { Direction::RightToLeft => region.cursor + child_move + vec2(-child_size.x, 0.0),
Direction::Horizontal => child_pos + vec2(-child_size.x, 0.0), Direction::TopDown => region.cursor + child_move,
Direction::Vertical => child_pos + vec2(0.0, -child_size.y), Direction::BottomUp => region.cursor + child_move + vec2(0.0, -child_size.y),
}; };
Rect::from_min_size(child_pos, child_size)
} else { Rect::from_min_size(child_pos, child_size)
let child_pos = region.cursor + child_move;
Rect::from_min_size(child_pos, child_size)
}
} }
} }
@ -343,24 +360,22 @@ impl Layout {
let align; let align;
match self.dir { match self.main_dir {
Direction::Horizontal => { Direction::LeftToRight => {
if self.reversed { painter.debug_arrow(cursor, vec2(1.0, 0.0), stroke);
painter.debug_arrow(cursor, vec2(-1.0, 0.0), stroke); align = (Align::Min, Align::Min);
align = (Align::Max, Align::Min);
} else {
painter.debug_arrow(cursor, vec2(1.0, 0.0), stroke);
align = (Align::Min, Align::Min);
}
} }
Direction::Vertical => { Direction::RightToLeft => {
if self.reversed { painter.debug_arrow(cursor, vec2(-1.0, 0.0), stroke);
painter.debug_arrow(cursor, vec2(0.0, -1.0), stroke); align = (Align::Max, Align::Min);
align = (Align::Min, Align::Max); }
} else { Direction::TopDown => {
painter.debug_arrow(cursor, vec2(0.0, 1.0), stroke); painter.debug_arrow(cursor, vec2(0.0, 1.0), stroke);
align = (Align::Min, Align::Min); align = (Align::Min, Align::Min);
} }
Direction::BottomUp => {
painter.debug_arrow(cursor, vec2(0.0, -1.0), stroke);
align = (Align::Min, Align::Max);
} }
} }

View file

@ -111,7 +111,10 @@ fn menu_impl<'c>(
style.visuals.widgets.inactive.bg_fill = TRANSPARENT; style.visuals.widgets.inactive.bg_fill = TRANSPARENT;
style.visuals.widgets.inactive.bg_stroke = Stroke::none(); style.visuals.widgets.inactive.bg_stroke = Stroke::none();
ui.set_style(style); ui.set_style(style);
ui.with_layout(Layout::justified(Direction::Vertical), add_contents); ui.with_layout(
Layout::top_down(Align::left()).with_cross_justify(true),
add_contents,
);
}) })
}); });

View file

@ -223,7 +223,7 @@ impl Ui {
/// Set the maximum width of the ui. /// Set the maximum width of the ui.
/// You won't be able to shrink it below the current minimum size. /// You won't be able to shrink it below the current minimum size.
pub fn set_max_width(&mut self, width: f32) { pub fn set_max_width(&mut self, width: f32) {
if self.layout.dir() == Direction::Horizontal && self.layout.is_reversed() { if self.layout.main_dir() == Direction::RightToLeft {
debug_assert_eq!(self.min_rect().max.x, self.max_rect().max.x); debug_assert_eq!(self.min_rect().max.x, self.max_rect().max.x);
self.region.max_rect.min.x = self.region.max_rect.min.x =
self.region.max_rect.max.x - width.at_least(self.min_rect().width()); self.region.max_rect.max.x - width.at_least(self.min_rect().width());
@ -237,7 +237,7 @@ impl Ui {
/// Set the maximum height of the ui. /// Set the maximum height of the ui.
/// You won't be able to shrink it below the current minimum size. /// You won't be able to shrink it below the current minimum size.
pub fn set_max_height(&mut self, height: f32) { pub fn set_max_height(&mut self, height: f32) {
if self.layout.dir() == Direction::Vertical && self.layout.is_reversed() { if self.layout.main_dir() == Direction::BottomUp {
debug_assert_eq!(self.min_rect().max.y, self.region.max_rect.max.y); debug_assert_eq!(self.min_rect().max.y, self.region.max_rect.max.y);
self.region.max_rect.min.y = self.region.max_rect.min.y =
self.region.max_rect.max.y - height.at_least(self.min_rect().height()); self.region.max_rect.max.y - height.at_least(self.min_rect().height());
@ -260,7 +260,7 @@ impl Ui {
/// Set the minimum width of the ui. /// Set the minimum width of the ui.
/// This can't shrink the ui, only make it larger. /// This can't shrink the ui, only make it larger.
pub fn set_min_width(&mut self, width: f32) { pub fn set_min_width(&mut self, width: f32) {
if self.layout.dir() == Direction::Horizontal && self.layout.is_reversed() { if self.layout.main_dir() == Direction::RightToLeft {
debug_assert_eq!(self.region.min_rect.max.x, self.region.max_rect.max.x); debug_assert_eq!(self.region.min_rect.max.x, self.region.max_rect.max.x);
let min_rect = &mut self.region.min_rect; let min_rect = &mut self.region.min_rect;
min_rect.min.x = min_rect.min.x.min(min_rect.max.x - width); min_rect.min.x = min_rect.min.x.min(min_rect.max.x - width);
@ -275,7 +275,7 @@ impl Ui {
/// Set the minimum height of the ui. /// Set the minimum height of the ui.
/// This can't shrink the ui, only make it larger. /// This can't shrink the ui, only make it larger.
pub fn set_min_height(&mut self, height: f32) { pub fn set_min_height(&mut self, height: f32) {
if self.layout.dir() == Direction::Vertical && self.layout.is_reversed() { if self.layout.main_dir() == Direction::BottomUp {
debug_assert_eq!(self.region.min_rect.max.y, self.region.max_rect.max.y); debug_assert_eq!(self.region.min_rect.max.y, self.region.max_rect.max.y);
let min_rect = &mut self.region.min_rect; let min_rect = &mut self.region.min_rect;
min_rect.min.y = min_rect.min.y.min(min_rect.max.y - height); min_rect.min.y = min_rect.min.y.min(min_rect.max.y - height);
@ -733,8 +733,9 @@ impl Ui {
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> (R, Response) { ) -> (R, Response) {
assert!( assert!(
self.layout().dir() == Direction::Vertical, self.layout.is_vertical(),
"You can only indent vertical layouts" "You can only indent vertical layouts, found {:?}",
self.layout
); );
let indent = vec2(self.style().spacing.indent, 0.0); let indent = vec2(self.style().spacing.indent, 0.0);
let child_rect = let child_rect =
@ -805,22 +806,19 @@ impl Ui {
self.style().spacing.interact_size.y, // Assume there will be something interactive on the horizontal layout self.style().spacing.interact_size.y, // Assume there will be something interactive on the horizontal layout
); );
let right_to_left = let layout = if self.layout.prefer_right_to_left() {
(self.layout.dir(), self.layout.align()) == (Direction::Vertical, Some(Align::Max)); Layout::right_to_left()
} else {
Layout::left_to_right()
};
self.allocate_ui_min(initial_size, |ui| { self.allocate_ui_min(initial_size, |ui| ui.with_layout(layout, add_contents).0)
ui.with_layout(
Layout::horizontal(Align::Center).with_reversed(right_to_left),
add_contents,
)
.0
})
} }
/// Start a ui with vertical layout. /// Start a ui with vertical layout.
/// Widgets will be left-justified. /// Widgets will be left-justified.
pub fn vertical<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Response) { pub fn vertical<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Response) {
self.with_layout(Layout::vertical(Align::Min), add_contents) self.with_layout(Layout::top_down(Align::Min), add_contents)
} }
pub fn with_layout<R>( pub fn with_layout<R>(

View file

@ -6,7 +6,7 @@
#![allow(clippy::new_without_default)] #![allow(clippy::new_without_default)]
use crate::{layout::Direction, *}; use crate::*;
pub mod color_picker; pub mod color_picker;
mod drag_value; mod drag_value;
@ -606,27 +606,24 @@ impl Widget for Separator {
let available_space = ui.available_finite().size(); let available_space = ui.available_finite().size();
let (points, rect) = match ui.layout().dir() { let (points, rect) = if ui.layout().main_dir().is_horizontal() {
Direction::Horizontal => { let rect = ui.allocate_space(vec2(spacing, available_space.y));
let rect = ui.allocate_space(vec2(spacing, available_space.y)); (
( [
[ pos2(rect.center().x, rect.top()),
pos2(rect.center().x, rect.top()), pos2(rect.center().x, rect.bottom()),
pos2(rect.center().x, rect.bottom()), ],
], rect,
rect, )
) } else {
} let rect = ui.allocate_space(vec2(available_space.x, spacing));
Direction::Vertical => { (
let rect = ui.allocate_space(vec2(available_space.x, spacing)); [
( pos2(rect.left(), rect.center().y),
[ pos2(rect.right(), rect.center().y),
pos2(rect.left(), rect.center().y), ],
pos2(rect.right(), rect.center().y), rect,
], )
rect,
)
}
}; };
let stroke = ui.style().visuals.widgets.noninteractive.bg_stroke; let stroke = ui.style().visuals.widgets.noninteractive.bg_stroke;
ui.painter().line_segment(points, stroke); ui.painter().line_segment(points, stroke);