Add Ui functions for doing manual layout ("put this widget here")
This commit is contained in:
parent
bca722ddf8
commit
df4c0257c0
8 changed files with 231 additions and 65 deletions
|
@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
* Add support for secondary and middle mouse buttons.
|
* Add support for secondary and middle mouse buttons.
|
||||||
* Add `Label` methods for code, strong, strikethrough, underline and italics.
|
* Add `Label` methods for code, strong, strikethrough, underline and italics.
|
||||||
* Add `ui.group(|ui| { … })` to visually group some widgets within a frame.
|
* Add `ui.group(|ui| { … })` to visually group some widgets within a frame.
|
||||||
|
* Add `Ui` helpers for doing manual layout (`ui.put`, `ui.allocate_ui_at_rect` and more).
|
||||||
* Add `ui.set_enabled(false)` to disable all widgets in a `Ui` (grayed out and non-interactive).
|
* Add `ui.set_enabled(false)` to disable all widgets in a `Ui` (grayed out and non-interactive).
|
||||||
* Add `TextEdit::hint_text` for showing a weak hint text when empty.
|
* Add `TextEdit::hint_text` for showing a weak hint text when empty.
|
||||||
* `egui::popup::popup_below_widget`: show a popup area below another widget.
|
* `egui::popup::popup_below_widget`: show a popup area below another widget.
|
||||||
|
|
|
@ -136,7 +136,7 @@ impl GridLayout {
|
||||||
Align2::LEFT_CENTER.align_size_within_rect(size, frame)
|
Align2::LEFT_CENTER.align_size_within_rect(size, frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn justify_or_align(&self, frame: Rect, size: Vec2) -> Rect {
|
pub(crate) fn justify_and_align(&self, frame: Rect, size: Vec2) -> Rect {
|
||||||
self.align_size_within_rect(size, frame)
|
self.align_size_within_rect(size, frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,12 @@ pub struct Layout {
|
||||||
/// wrap to a new row when we reach the right side of the `max_rect`.
|
/// wrap to a new row when we reach the right side of the `max_rect`.
|
||||||
main_wrap: bool,
|
main_wrap: bool,
|
||||||
|
|
||||||
|
/// How to align things on the main axis.
|
||||||
|
main_align: Align,
|
||||||
|
|
||||||
|
/// Justify the main axis?
|
||||||
|
main_justify: bool,
|
||||||
|
|
||||||
/// 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?
|
||||||
|
@ -133,6 +139,8 @@ impl Default for Layout {
|
||||||
Self {
|
Self {
|
||||||
main_dir: Direction::TopDown,
|
main_dir: Direction::TopDown,
|
||||||
main_wrap: false,
|
main_wrap: false,
|
||||||
|
main_align: Align::TOP,
|
||||||
|
main_justify: false,
|
||||||
cross_align: Align::LEFT,
|
cross_align: Align::LEFT,
|
||||||
cross_justify: false,
|
cross_justify: false,
|
||||||
}
|
}
|
||||||
|
@ -145,6 +153,8 @@ impl Layout {
|
||||||
Self {
|
Self {
|
||||||
main_dir: Direction::LeftToRight,
|
main_dir: Direction::LeftToRight,
|
||||||
main_wrap: false,
|
main_wrap: false,
|
||||||
|
main_align: Align::Center, // looks best to e.g. center text within a button
|
||||||
|
main_justify: false,
|
||||||
cross_align: Align::Center,
|
cross_align: Align::Center,
|
||||||
cross_justify: false,
|
cross_justify: false,
|
||||||
}
|
}
|
||||||
|
@ -154,6 +164,8 @@ impl Layout {
|
||||||
Self {
|
Self {
|
||||||
main_dir: Direction::RightToLeft,
|
main_dir: Direction::RightToLeft,
|
||||||
main_wrap: false,
|
main_wrap: false,
|
||||||
|
main_align: Align::Center, // looks best to e.g. center text within a button
|
||||||
|
main_justify: false,
|
||||||
cross_align: Align::Center,
|
cross_align: Align::Center,
|
||||||
cross_justify: false,
|
cross_justify: false,
|
||||||
}
|
}
|
||||||
|
@ -163,6 +175,8 @@ impl Layout {
|
||||||
Self {
|
Self {
|
||||||
main_dir: Direction::TopDown,
|
main_dir: Direction::TopDown,
|
||||||
main_wrap: false,
|
main_wrap: false,
|
||||||
|
main_align: Align::Center, // looks best to e.g. center text within a button
|
||||||
|
main_justify: false,
|
||||||
cross_align,
|
cross_align,
|
||||||
cross_justify: false,
|
cross_justify: false,
|
||||||
}
|
}
|
||||||
|
@ -177,6 +191,8 @@ impl Layout {
|
||||||
Self {
|
Self {
|
||||||
main_dir: Direction::BottomUp,
|
main_dir: Direction::BottomUp,
|
||||||
main_wrap: false,
|
main_wrap: false,
|
||||||
|
main_align: Align::Center, // looks best to e.g. center text within a button
|
||||||
|
main_justify: false,
|
||||||
cross_align,
|
cross_align,
|
||||||
cross_justify: false,
|
cross_justify: false,
|
||||||
}
|
}
|
||||||
|
@ -186,11 +202,24 @@ impl Layout {
|
||||||
Self {
|
Self {
|
||||||
main_dir,
|
main_dir,
|
||||||
main_wrap: false,
|
main_wrap: false,
|
||||||
|
main_align: Align::Center, // looks best to e.g. center text within a button
|
||||||
|
main_justify: false,
|
||||||
cross_align,
|
cross_align,
|
||||||
cross_justify: false,
|
cross_justify: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn centered_and_justified(main_dir: Direction) -> Self {
|
||||||
|
Self {
|
||||||
|
main_dir,
|
||||||
|
main_wrap: false,
|
||||||
|
main_align: Align::Center,
|
||||||
|
main_justify: true,
|
||||||
|
cross_align: Align::Center,
|
||||||
|
cross_justify: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[deprecated = "Use `top_down`"]
|
#[deprecated = "Use `top_down`"]
|
||||||
pub fn vertical(cross_align: Align) -> Self {
|
pub fn vertical(cross_align: Align) -> Self {
|
||||||
Self::top_down(cross_align)
|
Self::top_down(cross_align)
|
||||||
|
@ -252,22 +281,38 @@ impl Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn horizontal_align(&self) -> Align {
|
fn horizontal_align(&self) -> Align {
|
||||||
match self.main_dir {
|
if self.is_horizontal() {
|
||||||
// Direction::LeftToRight => Align::LEFT,
|
self.main_align
|
||||||
// Direction::RightToLeft => Align::right(),
|
} else {
|
||||||
Direction::LeftToRight | Direction::RightToLeft => Align::Center, // looks better to e.g. center text within a button
|
self.cross_align
|
||||||
|
|
||||||
Direction::TopDown | Direction::BottomUp => self.cross_align,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vertical_align(&self) -> Align {
|
fn vertical_align(&self) -> Align {
|
||||||
match self.main_dir {
|
if self.is_vertical() {
|
||||||
// Direction::TopDown => Align::TOP,
|
self.main_align
|
||||||
// Direction::BottomUp => Align::BOTTOM,
|
} else {
|
||||||
Direction::TopDown | Direction::BottomUp => Align::Center, // looks better to e.g. center text within a button
|
self.cross_align
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Direction::LeftToRight | Direction::RightToLeft => self.cross_align,
|
fn align2(&self) -> Align2 {
|
||||||
|
Align2([self.horizontal_align(), self.vertical_align()])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn horizontal_justify(&self) -> bool {
|
||||||
|
if self.is_horizontal() {
|
||||||
|
self.main_justify
|
||||||
|
} else {
|
||||||
|
self.cross_justify
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vertical_justify(&self) -> bool {
|
||||||
|
if self.is_vertical() {
|
||||||
|
self.main_justify
|
||||||
|
} else {
|
||||||
|
self.cross_justify
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,18 +320,7 @@ impl Layout {
|
||||||
/// ## Doing layout
|
/// ## Doing layout
|
||||||
impl Layout {
|
impl Layout {
|
||||||
pub fn align_size_within_rect(&self, size: Vec2, outer: Rect) -> Rect {
|
pub fn align_size_within_rect(&self, size: Vec2, outer: Rect) -> Rect {
|
||||||
let x = match self.horizontal_align() {
|
self.align2().align_size_within_rect(size, outer)
|
||||||
Align::Min => outer.left(),
|
|
||||||
Align::Center => outer.center().x - size.x / 2.0,
|
|
||||||
Align::Max => outer.right() - size.x,
|
|
||||||
};
|
|
||||||
let y = match self.vertical_align() {
|
|
||||||
Align::Min => outer.top(),
|
|
||||||
Align::Center => outer.center().y - size.y / 2.0,
|
|
||||||
Align::Max => outer.bottom() - size.y,
|
|
||||||
};
|
|
||||||
|
|
||||||
Rect::from_min_size(Pos2::new(x, y), size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initial_cursor(&self, max_rect: Rect) -> Pos2 {
|
fn initial_cursor(&self, max_rect: Rect) -> Pos2 {
|
||||||
|
@ -369,7 +403,7 @@ impl Layout {
|
||||||
/// Returns where to put the next widget that is of the given size.
|
/// Returns where to put the next widget that is of the given size.
|
||||||
/// The returned `frame_rect` `Rect` will always be justified along the cross axis.
|
/// The returned `frame_rect` `Rect` will always be justified along the cross axis.
|
||||||
/// This is what you then pass to `advance_after_rects`.
|
/// This is what you then pass to `advance_after_rects`.
|
||||||
/// Use `justify_or_align` to get the inner `widget_rect`.
|
/// Use `justify_and_align` to get the inner `widget_rect`.
|
||||||
#[allow(clippy::collapsible_if)]
|
#[allow(clippy::collapsible_if)]
|
||||||
pub(crate) fn next_space(
|
pub(crate) fn next_space(
|
||||||
&self,
|
&self,
|
||||||
|
@ -422,12 +456,12 @@ impl Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
let available_size = self.available_size_before_wrap_finite(region);
|
let available_size = self.available_size_before_wrap_finite(region);
|
||||||
if self.main_dir.is_horizontal() {
|
|
||||||
// Fill full height
|
if self.is_vertical() || self.horizontal_justify() {
|
||||||
child_size.y = child_size.y.max(available_size.y);
|
child_size.x = child_size.x.at_least(available_size.x); // fill full width
|
||||||
} else {
|
}
|
||||||
// Fill full width
|
if self.is_horizontal() || self.vertical_justify() {
|
||||||
child_size.x = child_size.x.max(available_size.x);
|
child_size.y = child_size.y.at_least(available_size.y); // fill full height
|
||||||
}
|
}
|
||||||
|
|
||||||
let child_pos = match self.main_dir {
|
let child_pos = match self.main_dir {
|
||||||
|
@ -440,30 +474,15 @@ impl Layout {
|
||||||
Rect::from_min_size(child_pos, child_size)
|
Rect::from_min_size(child_pos, child_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply justify or alignment after calling `next_space`.
|
/// Apply justify (fill width/height) and/or alignment after calling `next_space`.
|
||||||
pub(crate) fn justify_or_align(&self, rect: Rect, mut child_size: Vec2) -> Rect {
|
pub(crate) fn justify_and_align(&self, rect: Rect, mut child_size: Vec2) -> Rect {
|
||||||
if self.cross_justify {
|
if self.horizontal_justify() {
|
||||||
if self.main_dir.is_horizontal() {
|
child_size.x = child_size.x.at_least(rect.width()); // fill full width
|
||||||
child_size.y = rect.height(); // fill full height
|
|
||||||
} else {
|
|
||||||
child_size.x = rect.width(); // fill full width
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.main_dir {
|
|
||||||
Direction::LeftToRight => {
|
|
||||||
Align2([Align::Min, self.cross_align]).align_size_within_rect(child_size, rect)
|
|
||||||
}
|
|
||||||
Direction::RightToLeft => {
|
|
||||||
Align2([Align::Max, self.cross_align]).align_size_within_rect(child_size, rect)
|
|
||||||
}
|
|
||||||
Direction::TopDown => {
|
|
||||||
Align2([self.cross_align, Align::Min]).align_size_within_rect(child_size, rect)
|
|
||||||
}
|
|
||||||
Direction::BottomUp => {
|
|
||||||
Align2([self.cross_align, Align::Max]).align_size_within_rect(child_size, rect)
|
|
||||||
}
|
}
|
||||||
|
if self.vertical_justify() {
|
||||||
|
child_size.y = child_size.y.at_least(rect.height()); // fill full height
|
||||||
}
|
}
|
||||||
|
self.align_size_within_rect(child_size, rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Advance the cursor by this many points.
|
/// Advance the cursor by this many points.
|
||||||
|
|
|
@ -102,7 +102,7 @@ impl Placer {
|
||||||
/// Returns where to put the next widget that is of the given size.
|
/// Returns where to put the next widget that is of the given size.
|
||||||
/// The returned `frame_rect` will always be justified along the cross axis.
|
/// The returned `frame_rect` will always be justified along the cross axis.
|
||||||
/// This is what you then pass to `advance_after_rects`.
|
/// This is what you then pass to `advance_after_rects`.
|
||||||
/// Use `justify_or_align` to get the inner `widget_rect`.
|
/// Use `justify_and_align` to get the inner `widget_rect`.
|
||||||
pub(crate) fn next_space(&self, child_size: Vec2, item_spacing: Vec2) -> Rect {
|
pub(crate) fn next_space(&self, child_size: Vec2, item_spacing: Vec2) -> Rect {
|
||||||
if let Some(grid) = &self.grid {
|
if let Some(grid) = &self.grid {
|
||||||
grid.next_cell(self.region.cursor, child_size)
|
grid.next_cell(self.region.cursor, child_size)
|
||||||
|
@ -113,11 +113,11 @@ impl Placer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply justify or alignment after calling `next_space`.
|
/// Apply justify or alignment after calling `next_space`.
|
||||||
pub(crate) fn justify_or_align(&self, rect: Rect, child_size: Vec2) -> Rect {
|
pub(crate) fn justify_and_align(&self, rect: Rect, child_size: Vec2) -> Rect {
|
||||||
if let Some(grid) = &self.grid {
|
if let Some(grid) = &self.grid {
|
||||||
grid.justify_or_align(rect, child_size)
|
grid.justify_and_align(rect, child_size)
|
||||||
} else {
|
} else {
|
||||||
self.layout.justify_or_align(rect, child_size)
|
self.layout.justify_and_align(rect, child_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,9 @@ use crate::{
|
||||||
/// ui.label("A shorter and more convenient way to add a label.");
|
/// ui.label("A shorter and more convenient way to add a label.");
|
||||||
/// ui.horizontal(|ui| {
|
/// ui.horizontal(|ui| {
|
||||||
/// ui.label("Add widgets");
|
/// ui.label("Add widgets");
|
||||||
/// ui.button("on the same row!");
|
/// if ui.button("on the same row!").clicked() {
|
||||||
|
/// /* … */
|
||||||
|
/// }
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
|
@ -274,7 +276,7 @@ impl Ui {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
/// ## Sizes etc
|
/// # Sizes etc
|
||||||
impl Ui {
|
impl Ui {
|
||||||
/// Where and how large the `Ui` is already.
|
/// Where and how large the `Ui` is already.
|
||||||
/// All widgets that have been added ot this `Ui` fits within this rectangle.
|
/// All widgets that have been added ot this `Ui` fits within this rectangle.
|
||||||
|
@ -517,7 +519,10 @@ impl Ui {
|
||||||
pub fn advance_cursor(&mut self, amount: f32) {
|
pub fn advance_cursor(&mut self, amount: f32) {
|
||||||
self.placer.advance_cursor(amount);
|
self.placer.advance_cursor(amount);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Allocating space: where do I put my widgets?
|
||||||
|
impl Ui {
|
||||||
/// Allocate space for a widget and check for interaction in the space.
|
/// Allocate space for a widget and check for interaction in the space.
|
||||||
/// Returns a `Response` which contains a rectangle, id, and interaction info.
|
/// Returns a `Response` which contains a rectangle, id, and interaction info.
|
||||||
///
|
///
|
||||||
|
@ -629,7 +634,7 @@ impl Ui {
|
||||||
fn allocate_space_impl(&mut self, desired_size: Vec2) -> Rect {
|
fn allocate_space_impl(&mut self, desired_size: Vec2) -> Rect {
|
||||||
let item_spacing = self.spacing().item_spacing;
|
let item_spacing = self.spacing().item_spacing;
|
||||||
let frame_rect = self.placer.next_space(desired_size, item_spacing);
|
let frame_rect = self.placer.next_space(desired_size, item_spacing);
|
||||||
let widget_rect = self.placer.justify_or_align(frame_rect, desired_size);
|
let widget_rect = self.placer.justify_and_align(frame_rect, desired_size);
|
||||||
|
|
||||||
self.placer
|
self.placer
|
||||||
.advance_after_rects(frame_rect, widget_rect, item_spacing);
|
.advance_after_rects(frame_rect, widget_rect, item_spacing);
|
||||||
|
@ -637,7 +642,8 @@ impl Ui {
|
||||||
widget_rect
|
widget_rect
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate a specific part of the ui.
|
/// Allocate a specific part of the `Ui‘.
|
||||||
|
/// Ignore the layout of the `Ui‘: just put my widget here!
|
||||||
pub(crate) fn allocate_rect(&mut self, rect: Rect, sense: Sense) -> Response {
|
pub(crate) fn allocate_rect(&mut self, rect: Rect, sense: Sense) -> Response {
|
||||||
let id = self.advance_cursor_after_rect(rect);
|
let id = self.advance_cursor_after_rect(rect);
|
||||||
self.interact(rect, id, sense)
|
self.interact(rect, id, sense)
|
||||||
|
@ -666,7 +672,9 @@ impl Ui {
|
||||||
) -> (R, Response) {
|
) -> (R, Response) {
|
||||||
let item_spacing = self.spacing().item_spacing;
|
let item_spacing = self.spacing().item_spacing;
|
||||||
let outer_child_rect = self.placer.next_space(desired_size, item_spacing);
|
let outer_child_rect = self.placer.next_space(desired_size, item_spacing);
|
||||||
let inner_child_rect = self.placer.justify_or_align(outer_child_rect, desired_size);
|
let inner_child_rect = self
|
||||||
|
.placer
|
||||||
|
.justify_and_align(outer_child_rect, desired_size);
|
||||||
|
|
||||||
let mut child_ui = self.child_ui(inner_child_rect, *self.layout());
|
let mut child_ui = self.child_ui(inner_child_rect, *self.layout());
|
||||||
let ret = add_contents(&mut child_ui);
|
let ret = add_contents(&mut child_ui);
|
||||||
|
@ -682,6 +690,29 @@ impl Ui {
|
||||||
(ret, response)
|
(ret, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocated the given rectangle and then adds content to that rectangle.
|
||||||
|
/// If the contents overflow, more space will be allocated.
|
||||||
|
/// When finished, the amount of space actually used (`min_rect`) will be allocated.
|
||||||
|
/// So you can request a lot of space and then use less.
|
||||||
|
pub fn allocate_ui_at_rect<R>(
|
||||||
|
&mut self,
|
||||||
|
max_rect: Rect,
|
||||||
|
add_contents: impl FnOnce(&mut Self) -> R,
|
||||||
|
) -> (R, Response) {
|
||||||
|
let mut child_ui = self.child_ui(max_rect, *self.layout());
|
||||||
|
let ret = add_contents(&mut child_ui);
|
||||||
|
let final_child_rect = child_ui.min_rect();
|
||||||
|
|
||||||
|
self.placer.advance_after_rects(
|
||||||
|
final_child_rect,
|
||||||
|
final_child_rect,
|
||||||
|
self.spacing().item_spacing,
|
||||||
|
);
|
||||||
|
|
||||||
|
let response = self.interact(final_child_rect, child_ui.id, Sense::hover());
|
||||||
|
(ret, response)
|
||||||
|
}
|
||||||
|
|
||||||
/// Convenience function to get a region to paint on
|
/// Convenience function to get a region to paint on
|
||||||
pub fn allocate_painter(&mut self, desired_size: Vec2, sense: Sense) -> (Response, Painter) {
|
pub fn allocate_painter(&mut self, desired_size: Vec2, sense: Sense) -> (Response, Painter) {
|
||||||
let response = self.allocate_response(desired_size, sense);
|
let response = self.allocate_response(desired_size, sense);
|
||||||
|
@ -729,6 +760,22 @@ impl Ui {
|
||||||
widget.ui(self)
|
widget.ui(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a widget to this `Ui` with a given max size.
|
||||||
|
pub fn add_sized(&mut self, max_size: Vec2, widget: impl Widget) -> Response {
|
||||||
|
self.allocate_ui(max_size, |ui| {
|
||||||
|
ui.centered_and_justified(|ui| ui.add(widget)).0
|
||||||
|
})
|
||||||
|
.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a widget to this `Ui` at a specific location (manual layout).
|
||||||
|
pub fn put(&mut self, max_rect: Rect, widget: impl Widget) -> Response {
|
||||||
|
self.allocate_ui_at_rect(max_rect, |ui| {
|
||||||
|
ui.centered_and_justified(|ui| ui.add(widget)).0
|
||||||
|
})
|
||||||
|
.0
|
||||||
|
}
|
||||||
|
|
||||||
/// Shortcut for `add(Label::new(text))`
|
/// Shortcut for `add(Label::new(text))`
|
||||||
pub fn label(&mut self, label: impl Into<Label>) -> Response {
|
pub fn label(&mut self, label: impl Into<Label>) -> Response {
|
||||||
self.add(label.into())
|
self.add(label.into())
|
||||||
|
@ -1256,6 +1303,17 @@ impl Ui {
|
||||||
(ret, self.interact(rect, child_ui.id, Sense::hover()))
|
(ret, self.interact(rect, child_ui.id, Sense::hover()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This will make the next added widget centered and justified in the available space.
|
||||||
|
pub fn centered_and_justified<R>(
|
||||||
|
&mut self,
|
||||||
|
add_contents: impl FnOnce(&mut Self) -> R,
|
||||||
|
) -> (R, Response) {
|
||||||
|
self.with_layout(
|
||||||
|
Layout::centered_and_justified(Direction::TopDown),
|
||||||
|
add_contents,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn set_grid(&mut self, grid: grid::GridLayout) {
|
pub(crate) fn set_grid(&mut self, grid: grid::GridLayout) {
|
||||||
self.placer.set_grid(grid);
|
self.placer.set_grid(grid);
|
||||||
}
|
}
|
||||||
|
@ -1332,7 +1390,7 @@ impl Ui {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// ## Debug stuff
|
/// # Debug stuff
|
||||||
impl Ui {
|
impl Ui {
|
||||||
/// Shows where the next widget is going to be placed
|
/// Shows where the next widget is going to be placed
|
||||||
pub fn debug_paint_cursor(&self) {
|
pub fn debug_paint_cursor(&self) {
|
||||||
|
|
|
@ -22,10 +22,11 @@ impl Default for Demos {
|
||||||
Box::new(super::widget_gallery::WidgetGallery::default()),
|
Box::new(super::widget_gallery::WidgetGallery::default()),
|
||||||
Box::new(super::window_options::WindowOptions::default()),
|
Box::new(super::window_options::WindowOptions::default()),
|
||||||
// Tests:
|
// Tests:
|
||||||
Box::new(super::layout_test::LayoutTest::default()),
|
|
||||||
Box::new(super::tests::IdTest::default()),
|
Box::new(super::tests::IdTest::default()),
|
||||||
Box::new(super::tests::TableTest::default()),
|
|
||||||
Box::new(super::tests::InputTest::default()),
|
Box::new(super::tests::InputTest::default()),
|
||||||
|
Box::new(super::layout_test::LayoutTest::default()),
|
||||||
|
Box::new(super::tests::ManualLayoutTest::default()),
|
||||||
|
Box::new(super::tests::TableTest::default()),
|
||||||
];
|
];
|
||||||
Self {
|
Self {
|
||||||
open: vec![false; demos.len()],
|
open: vec![false; demos.len()],
|
||||||
|
|
|
@ -52,6 +52,91 @@ impl super::View for IdTest {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
enum WidgetType {
|
||||||
|
Label,
|
||||||
|
Button,
|
||||||
|
TextEdit,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ManualLayoutTest {
|
||||||
|
widget_offset: egui::Vec2,
|
||||||
|
widget_size: egui::Vec2,
|
||||||
|
widget_type: WidgetType,
|
||||||
|
text_edit_contents: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ManualLayoutTest {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
widget_offset: egui::Vec2::splat(150.0),
|
||||||
|
widget_size: egui::Vec2::new(200.0, 100.0),
|
||||||
|
widget_type: WidgetType::Button,
|
||||||
|
text_edit_contents: crate::LOREM_IPSUM.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::Demo for ManualLayoutTest {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"Manual Layout Test"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show(&mut self, ctx: &egui::CtxRef, open: &mut bool) {
|
||||||
|
egui::Window::new(self.name()).open(open).show(ctx, |ui| {
|
||||||
|
use super::View;
|
||||||
|
self.ui(ui);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::View for ManualLayoutTest {
|
||||||
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
|
use egui::*;
|
||||||
|
reset_button(ui, self);
|
||||||
|
let Self {
|
||||||
|
widget_offset,
|
||||||
|
widget_size,
|
||||||
|
widget_type,
|
||||||
|
text_edit_contents,
|
||||||
|
} = self;
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Test widget:");
|
||||||
|
ui.radio_value(widget_type, WidgetType::Button, "Button");
|
||||||
|
ui.radio_value(widget_type, WidgetType::Label, "Label");
|
||||||
|
ui.radio_value(widget_type, WidgetType::TextEdit, "TextEdit");
|
||||||
|
});
|
||||||
|
Grid::new("pos_size").show(ui, |ui| {
|
||||||
|
ui.label("Widget position:");
|
||||||
|
ui.add(Slider::f32(&mut widget_offset.x, 0.0..=400.0));
|
||||||
|
ui.add(Slider::f32(&mut widget_offset.y, 0.0..=400.0));
|
||||||
|
ui.end_row();
|
||||||
|
|
||||||
|
ui.label("Widget size:");
|
||||||
|
ui.add(Slider::f32(&mut widget_size.x, 0.0..=400.0));
|
||||||
|
ui.add(Slider::f32(&mut widget_size.y, 0.0..=400.0));
|
||||||
|
ui.end_row();
|
||||||
|
});
|
||||||
|
let widget_rect = Rect::from_min_size(ui.min_rect().min + *widget_offset, *widget_size);
|
||||||
|
|
||||||
|
// Showing how to place a widget anywhere in the `Ui`:
|
||||||
|
match *widget_type {
|
||||||
|
WidgetType::Button => {
|
||||||
|
ui.put(widget_rect, Button::new("Example button"));
|
||||||
|
}
|
||||||
|
WidgetType::Label => {
|
||||||
|
ui.put(widget_rect, Label::new("Example label"));
|
||||||
|
}
|
||||||
|
WidgetType::TextEdit => {
|
||||||
|
ui.put(widget_rect, TextEdit::multiline(text_edit_contents));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
pub struct TableTest {
|
pub struct TableTest {
|
||||||
num_cols: usize,
|
num_cols: usize,
|
||||||
num_rows: usize,
|
num_rows: usize,
|
||||||
|
|
|
@ -62,6 +62,8 @@ impl super::View for WidgetGallery {
|
||||||
});
|
});
|
||||||
ui.set_enabled(*enabled);
|
ui.set_enabled(*enabled);
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
let grid = egui::Grid::new("my_grid")
|
let grid = egui::Grid::new("my_grid")
|
||||||
.striped(true)
|
.striped(true)
|
||||||
.spacing([40.0, 4.0]);
|
.spacing([40.0, 4.0]);
|
||||||
|
|
Loading…
Reference in a new issue