1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-27 23:13:13 -04:00

Reverted the demos back

This commit is contained in:
Konkitoman
2023-08-04 10:18:24 +03:00
parent e8027b3c3a
commit 6a7d162d40
19 changed files with 304 additions and 549 deletions

View File

@@ -14,7 +14,7 @@ impl super::Demo for About {
.open(open)
.show(ctx, |ui| {
use super::View as _;
Self::default().ui(ui);
self.ui(ui);
});
}
}

View File

@@ -1,21 +1,12 @@
use std::sync::{Arc, RwLock};
// ----------------------------------------------------------------------------
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct CodeEditorData {
pub struct CodeEditor {
language: String,
code: String,
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[derive(Default, Clone)]
pub struct CodeEditor {
data: Arc<RwLock<CodeEditorData>>,
}
impl Default for CodeEditorData {
impl Default for CodeEditor {
fn default() -> Self {
Self {
language: "rs".into(),
@@ -35,18 +26,17 @@ impl super::Demo for CodeEditor {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
use super::View as _;
egui::Window::new(self.name())
.open(open)
.default_height(500.0)
.show(ctx, move |ui| clone.clone().ui(ui));
.show(ctx, move |ui| self.ui(ui));
}
}
impl super::View for CodeEditor {
fn ui(&mut self, ui: &mut egui::Ui) {
let CodeEditorData { language, code } = &mut *self.data.write().unwrap();
let CodeEditor { language, code } = self;
ui.horizontal(|ui| {
ui.set_height(0.0);

View File

@@ -1,17 +1,10 @@
use std::sync::{Arc, RwLock};
#[derive(Debug)]
pub struct CodeExampleData {
pub struct CodeExample {
name: String,
age: u32,
}
#[derive(Debug, Default, Clone)]
pub struct CodeExample {
data: Arc<RwLock<CodeExampleData>>,
}
impl Default for CodeExampleData {
impl Default for CodeExample {
fn default() -> Self {
Self {
name: "Arthur".to_owned(),
@@ -36,29 +29,28 @@ impl CodeExample {
});"#,
);
// Putting things on the same line using ui.horizontal:
let mut data = self.data.write().unwrap();
ui.horizontal(|ui| {
ui.label("Your name: ");
ui.text_edit_singleline(&mut data.name);
ui.text_edit_singleline(&mut self.name);
});
ui.end_row();
show_code(
ui,
r#"egui::Slider::new(&mut data.age, 0..=120).text("age")"#,
r#"egui::Slider::new(&mut self.age, 0..=120).text("age")"#,
);
ui.add(egui::Slider::new(&mut data.age, 0..=120).text("age"));
ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));
ui.end_row();
show_code(
ui,
r#"
if ui.button("Click each year").clicked() {
data.age += 1;
self.age += 1;
}"#,
);
if ui.button("Click each year").clicked() {
data.age += 1;
self.age += 1;
}
ui.end_row();
@@ -66,7 +58,7 @@ impl CodeExample {
ui,
r#"ui.label(format!("Hello '{}', age {}", self.name, self.age));"#,
);
ui.label(format!("Hello '{}', age {}", data.name, data.age));
ui.label(format!("Hello '{}', age {}", self.name, self.age));
ui.end_row();
}
}
@@ -77,14 +69,13 @@ impl super::Demo for CodeExample {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
use super::View;
egui::Window::new(self.name())
.open(open)
.default_size([800.0, 400.0])
.vscroll(false)
.hscroll(true)
.show(ctx, move |ui| clone.clone().ui(ui));
.show(ctx, move |ui| self.ui(ui));
}
}

View File

@@ -1,5 +1,3 @@
use std::sync::{Arc, RwLock};
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
enum Plot {
@@ -16,9 +14,10 @@ fn gaussian(x: f64) -> f64 {
fn sigmoid(x: f64) -> f64 {
-1.0 + 2.0 / (1.0 + f64::exp(-x))
}
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ContextMenusData {
pub struct ContextMenus {
plot: Plot,
show_axes: [bool; 2],
allow_drag: bool,
@@ -30,19 +29,7 @@ pub struct ContextMenusData {
height: f32,
}
#[derive(Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ContextMenus {
data: Arc<RwLock<ContextMenusData>>,
}
impl PartialEq for ContextMenus {
fn eq(&self, other: &Self) -> bool {
*self.data.read().unwrap() == *other.data.read().unwrap()
}
}
impl Default for ContextMenusData {
impl Default for ContextMenus {
fn default() -> Self {
Self {
plot: Plot::Sin,
@@ -64,13 +51,12 @@ impl super::Demo for ContextMenus {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
use super::View;
egui::Window::new(self.name())
.vscroll(false)
.resizable(false)
.open(open)
.show(ctx, move |ui| clone.clone().ui(ui));
.show(ctx, move |ui| self.ui(ui));
}
}
@@ -87,14 +73,13 @@ impl super::View for ContextMenus {
ui.label("Right-click plot to edit it!");
ui.horizontal(|ui| {
self.example_plot(ui).context_menu(|ui| {
let data = &mut *self.data.write().unwrap();
ui.menu_button("Plot", |ui| {
if ui.radio_value(&mut data.plot, Plot::Sin, "Sin").clicked()
if ui.radio_value(&mut self.plot, Plot::Sin, "Sin").clicked()
|| ui
.radio_value(&mut data.plot, Plot::Bell, "Gaussian")
.radio_value(&mut self.plot, Plot::Bell, "Gaussian")
.clicked()
|| ui
.radio_value(&mut data.plot, Plot::Sigmoid, "Sigmoid")
.radio_value(&mut self.plot, Plot::Sigmoid, "Sigmoid")
.clicked()
{
ui.close_menu();
@@ -102,22 +87,22 @@ impl super::View for ContextMenus {
});
egui::Grid::new("button_grid").show(ui, |ui| {
ui.add(
egui::DragValue::new(&mut data.width)
egui::DragValue::new(&mut self.width)
.speed(1.0)
.prefix("Width:"),
);
ui.add(
egui::DragValue::new(&mut data.height)
egui::DragValue::new(&mut self.height)
.speed(1.0)
.prefix("Height:"),
);
ui.end_row();
ui.checkbox(&mut data.show_axes[0], "x-Axis");
ui.checkbox(&mut data.show_axes[1], "y-Axis");
ui.checkbox(&mut self.show_axes[0], "x-Axis");
ui.checkbox(&mut self.show_axes[1], "y-Axis");
ui.end_row();
if ui.checkbox(&mut data.allow_drag, "Drag").changed()
|| ui.checkbox(&mut data.allow_zoom, "Zoom").changed()
|| ui.checkbox(&mut data.allow_scroll, "Scroll").changed()
if ui.checkbox(&mut self.allow_drag, "Drag").changed()
|| ui.checkbox(&mut self.allow_zoom, "Zoom").changed()
|| ui.checkbox(&mut self.allow_scroll, "Scroll").changed()
{
ui.close_menu();
}
@@ -132,7 +117,6 @@ impl super::View for ContextMenus {
impl ContextMenus {
fn example_plot(&self, ui: &mut egui::Ui) -> egui::Response {
let data = &mut *self.data.write().unwrap();
use egui::plot::{Line, PlotPoints};
let n = 128;
let line = Line::new(
@@ -140,7 +124,7 @@ impl ContextMenus {
.map(|i| {
use std::f64::consts::TAU;
let x = egui::remap(i as f64, 0.0..=n as f64, -TAU..=TAU);
match data.plot {
match self.plot {
Plot::Sin => [x, x.sin()],
Plot::Bell => [x, 10.0 * gaussian(x)],
Plot::Sigmoid => [x, sigmoid(x)],
@@ -149,14 +133,14 @@ impl ContextMenus {
.collect::<PlotPoints>(),
);
egui::plot::Plot::new("example_plot")
.show_axes(data.show_axes)
.allow_drag(data.allow_drag)
.allow_zoom(data.allow_zoom)
.allow_scroll(data.allow_scroll)
.center_x_axis(data.center_x_axis)
.center_x_axis(data.center_y_axis)
.width(data.width)
.height(data.height)
.show_axes(self.show_axes)
.allow_drag(self.allow_drag)
.allow_zoom(self.allow_zoom)
.allow_scroll(self.allow_scroll)
.center_x_axis(self.center_x_axis)
.center_x_axis(self.center_y_axis)
.width(self.width)
.height(self.height)
.data_aspect(1.0)
.show(ui, |plot_ui| plot_ui.line(line))
.response

View File

@@ -1,5 +1,3 @@
use std::sync::{Arc, RwLock};
use egui::*;
pub fn drag_source(ui: &mut Ui, id: Id, body: impl FnOnce(&mut Ui)) {
@@ -77,32 +75,23 @@ pub fn drop_target<R>(
InnerResponse::new(ret, response)
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct DragAndDropDemo {
/// columns with items
columns: Arc<RwLock<Vec<Vec<String>>>>,
}
impl PartialEq for DragAndDropDemo {
fn eq(&self, other: &Self) -> bool {
*self.columns.read().unwrap() == *other.columns.read().unwrap()
}
columns: Vec<Vec<String>>,
}
impl Default for DragAndDropDemo {
fn default() -> Self {
Self {
columns: Arc::new(RwLock::new(
vec![
vec!["Item A", "Item B", "Item C"],
vec!["Item D", "Item E"],
vec!["Item F", "Item G", "Item H"],
]
.into_iter()
.map(|v| v.into_iter().map(ToString::to_string).collect())
.collect(),
)),
columns: vec![
vec!["Item A", "Item B", "Item C"],
vec!["Item D", "Item E"],
vec!["Item F", "Item G", "Item H"],
]
.into_iter()
.map(|v| v.into_iter().map(ToString::to_string).collect())
.collect(),
}
}
}
@@ -113,14 +102,13 @@ impl super::Demo for DragAndDropDemo {
}
fn show(&mut self, ctx: &Context, open: &mut bool) {
let clone = self.clone();
use super::View as _;
Window::new(self.name())
.open(open)
.default_size(vec2(256.0, 256.0))
.vscroll(false)
.resizable(false)
.show(ctx, move |ui| clone.clone().ui(ui));
.show(ctx, move |ui| self.ui(ui));
}
}
@@ -132,7 +120,7 @@ impl super::View for DragAndDropDemo {
let id_source = "my_drag_and_drop_demo";
let mut source_col_row = None;
let mut drop_col = None;
let mut columns = self.columns.write().unwrap();
let columns = &mut self.columns;
ui.columns(columns.len(), |uis| {
for (col_idx, column) in columns.clone().into_iter().enumerate() {
let ui = &mut uis[col_idx];

View File

@@ -1,19 +1,11 @@
use std::{
collections::BTreeMap,
sync::{Arc, RwLock},
};
pub struct FontBookData {
use std::collections::BTreeMap;
pub struct FontBook {
filter: String,
font_id: egui::FontId,
named_chars: BTreeMap<egui::FontFamily, BTreeMap<char, String>>,
}
#[derive(Default, Clone)]
pub struct FontBook {
data: Arc<RwLock<FontBookData>>,
}
impl Default for FontBookData {
impl Default for FontBook {
fn default() -> Self {
Self {
filter: Default::default(),
@@ -29,12 +21,11 @@ impl super::Demo for FontBook {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
@@ -45,12 +36,10 @@ impl super::View for FontBook {
ui.add(crate::egui_github_link_file!());
});
let data = &mut *self.data.write().unwrap();
ui.label(format!(
"The selected font supports {} characters.",
data.named_chars
.get(&data.font_id.family)
self.named_chars
.get(&self.font_id.family)
.map(|map| map.len())
.unwrap_or_default()
));
@@ -67,22 +56,22 @@ impl super::View for FontBook {
ui.separator();
egui::introspection::font_id_ui(ui, &mut data.font_id);
egui::introspection::font_id_ui(ui, &mut self.font_id);
ui.horizontal(|ui| {
ui.label("Filter:");
ui.add(egui::TextEdit::singleline(&mut data.filter).desired_width(120.0));
data.filter = data.filter.to_lowercase();
ui.add(egui::TextEdit::singleline(&mut self.filter).desired_width(120.0));
self.filter = self.filter.to_lowercase();
if ui.button("").clicked() {
data.filter.clear();
self.filter.clear();
}
});
let filter = &data.filter;
let named_chars = data
let filter = &self.filter;
let named_chars = self
.named_chars
.entry(data.font_id.family.clone())
.or_insert_with(|| available_characters(ui, data.font_id.family.clone()));
.entry(self.font_id.family.clone())
.or_insert_with(|| available_characters(ui, self.font_id.family.clone()));
ui.separator();
@@ -93,13 +82,13 @@ impl super::View for FontBook {
for (&chr, name) in named_chars {
if filter.is_empty() || name.contains(filter) || *filter == chr.to_string() {
let button = egui::Button::new(
egui::RichText::new(chr.to_string()).font(data.font_id.clone()),
egui::RichText::new(chr.to_string()).font(self.font_id.clone()),
)
.frame(false);
let tooltip_ui = |ui: &mut egui::Ui| {
ui.label(
egui::RichText::new(chr.to_string()).font(data.font_id.clone()),
egui::RichText::new(chr.to_string()).font(self.font_id.clone()),
);
ui.label(format!("{}\nU+{:X}\n\nClick to copy", name, chr as u32));
};

View File

@@ -1,10 +1,8 @@
use std::sync::{Arc, RwLock};
use egui::*;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct LayoutTestData {
pub struct LayoutTest {
// Identical to contents of `egui::Layout`
layout: LayoutSettings,
@@ -13,14 +11,7 @@ pub struct LayoutTestData {
wrap_row_height: f32,
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[derive(Default, Clone)]
pub struct LayoutTest {
data: Arc<RwLock<LayoutTestData>>,
}
impl Default for LayoutTestData {
impl Default for LayoutTest {
fn default() -> Self {
Self {
layout: LayoutSettings::top_down(),
@@ -88,13 +79,12 @@ impl super::Demo for LayoutTest {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.resizable(false)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
@@ -103,24 +93,23 @@ impl super::View for LayoutTest {
fn ui(&mut self, ui: &mut Ui) {
ui.label("Tests and demonstrates the limits of the egui layouts");
self.content_ui(ui);
let data = self.data.write().unwrap();
Resize::default()
.default_size([150.0, 200.0])
.show(ui, |ui| {
if data.layout.main_wrap {
if data.layout.main_dir.is_horizontal() {
if self.layout.main_wrap {
if self.layout.main_dir.is_horizontal() {
ui.allocate_ui(
vec2(ui.available_size_before_wrap().x, data.wrap_row_height),
|ui| ui.with_layout(data.layout.layout(), demo_ui),
vec2(ui.available_size_before_wrap().x, self.wrap_row_height),
|ui| ui.with_layout(self.layout.layout(), demo_ui),
);
} else {
ui.allocate_ui(
vec2(data.wrap_column_width, ui.available_size_before_wrap().y),
|ui| ui.with_layout(data.layout.layout(), demo_ui),
vec2(self.wrap_column_width, ui.available_size_before_wrap().y),
|ui| ui.with_layout(self.layout.layout(), demo_ui),
);
}
} else {
ui.with_layout(data.layout.layout(), demo_ui);
ui.with_layout(self.layout.layout(), demo_ui);
}
});
ui.label("Resize to see effect");
@@ -129,16 +118,15 @@ impl super::View for LayoutTest {
impl LayoutTest {
pub fn content_ui(&mut self, ui: &mut Ui) {
let mut data = self.data.write().unwrap();
ui.horizontal(|ui| {
ui.selectable_value(&mut data.layout, LayoutSettings::top_down(), "Top-down");
ui.selectable_value(&mut self.layout, LayoutSettings::top_down(), "Top-down");
ui.selectable_value(
&mut data.layout,
&mut self.layout,
LayoutSettings::top_down_justified_centered(),
"Top-down, centered and justified",
);
ui.selectable_value(
&mut data.layout,
&mut self.layout,
LayoutSettings::horizontal_wrapped(),
"Horizontal wrapped",
);
@@ -152,20 +140,20 @@ impl LayoutTest {
Direction::TopDown,
Direction::BottomUp,
] {
ui.radio_value(&mut data.layout.main_dir, dir, format!("{:?}", dir));
ui.radio_value(&mut self.layout.main_dir, dir, format!("{:?}", dir));
}
});
ui.horizontal(|ui| {
ui.checkbox(&mut data.layout.main_wrap, "Main wrap")
ui.checkbox(&mut self.layout.main_wrap, "Main wrap")
.on_hover_text("Wrap when next widget doesn't fit the current row/column");
if data.layout.main_wrap {
if data.layout.main_dir.is_horizontal() {
ui.add(Slider::new(&mut data.wrap_row_height, 0.0..=200.0).text("Row height"));
if self.layout.main_wrap {
if self.layout.main_dir.is_horizontal() {
ui.add(Slider::new(&mut self.wrap_row_height, 0.0..=200.0).text("Row height"));
} else {
ui.add(
Slider::new(&mut data.wrap_column_width, 0.0..=200.0).text("Column width"),
Slider::new(&mut self.wrap_column_width, 0.0..=200.0).text("Column width"),
);
}
}
@@ -174,11 +162,11 @@ impl LayoutTest {
ui.horizontal(|ui| {
ui.label("Cross Align:");
for &align in &[Align::Min, Align::Center, Align::Max] {
ui.radio_value(&mut data.layout.cross_align, align, format!("{:?}", align));
ui.radio_value(&mut self.layout.cross_align, align, format!("{:?}", align));
}
});
ui.checkbox(&mut data.layout.cross_justify, "Cross Justified")
ui.checkbox(&mut self.layout.cross_justify, "Cross Justified")
.on_hover_text("Try to fill full width/height (e.g. buttons)");
}
}

View File

@@ -1,12 +1,11 @@
use std::sync::{Arc, RwLock};
use super::*;
use crate::LOREM_IPSUM;
use egui::{epaint::text::TextWrapping, *};
/// Showcase some ui code
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct MiscDemoWindowData {
pub struct MiscDemoWindow {
num_columns: usize,
break_anywhere: bool,
@@ -22,17 +21,10 @@ pub struct MiscDemoWindowData {
dummy_bool: bool,
dummy_usize: usize,
}
/// Showcase some ui code
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[derive(Default, Clone)]
pub struct MiscDemoWindow {
data: Arc<RwLock<MiscDemoWindowData>>,
}
impl Default for MiscDemoWindowData {
fn default() -> MiscDemoWindowData {
MiscDemoWindowData {
impl Default for MiscDemoWindow {
fn default() -> MiscDemoWindow {
MiscDemoWindow {
num_columns: 2,
max_rows: 2,
@@ -57,12 +49,11 @@ impl Demo for MiscDemoWindow {
}
fn show(&mut self, ctx: &Context, open: &mut bool) {
let clone = self.clone();
Window::new(self.name())
.open(open)
.vscroll(true)
.hscroll(true)
.show(ctx, move |ui| clone.clone().ui(ui));
.show(ctx, move |ui| self.ui(ui));
}
}
@@ -70,13 +61,10 @@ impl View for MiscDemoWindow {
fn ui(&mut self, ui: &mut Ui) {
ui.set_min_width(250.0);
let mut data = self.data.write().unwrap();
let data = &mut *data;
CollapsingHeader::new("Widgets")
.default_open(true)
.show(ui, |ui| {
data.widgets.ui(ui);
self.widgets.ui(ui);
});
CollapsingHeader::new("Text layout")
@@ -84,25 +72,25 @@ impl View for MiscDemoWindow {
.show(ui, |ui| {
text_layout_ui(
ui,
&mut data.max_rows,
&mut data.break_anywhere,
&mut data.overflow_character,
&mut self.max_rows,
&mut self.break_anywhere,
&mut self.overflow_character,
);
});
CollapsingHeader::new("Colors")
.default_open(false)
.show(ui, |ui| {
data.colors.ui(ui);
self.colors.ui(ui);
});
CollapsingHeader::new("Custom Collapsing Header")
.default_open(false)
.show(ui, |ui| data.custom_collapsing_header.ui(ui));
.show(ui, |ui| self.custom_collapsing_header.ui(ui));
CollapsingHeader::new("Tree")
.default_open(false)
.show(ui, |ui| data.tree.ui(ui));
.show(ui, |ui| self.tree.ui(ui));
CollapsingHeader::new("Checkboxes")
.default_open(false)
@@ -111,28 +99,28 @@ impl View for MiscDemoWindow {
ui.spacing_mut().item_spacing = Vec2::ZERO;
ui.horizontal_wrapped(|ui| {
for _ in 0..64 {
ui.checkbox(&mut data.dummy_bool, "");
ui.checkbox(&mut self.dummy_bool, "");
}
});
ui.checkbox(&mut data.dummy_bool, "checkbox");
ui.checkbox(&mut self.dummy_bool, "checkbox");
ui.label("Radiobuttons are similar:");
ui.spacing_mut().item_spacing = Vec2::ZERO;
ui.horizontal_wrapped(|ui| {
for i in 0..64 {
ui.radio_value(&mut data.dummy_usize, i, "");
ui.radio_value(&mut self.dummy_usize, i, "");
}
});
ui.radio_value(&mut data.dummy_usize, 64, "radio_value");
ui.radio_value(&mut self.dummy_usize, 64, "radio_value");
});
ui.collapsing("Columns", |ui| {
ui.add(Slider::new(&mut data.num_columns, 1..=10).text("Columns"));
ui.columns(data.num_columns, |cols| {
ui.add(Slider::new(&mut self.num_columns, 1..=10).text("Columns"));
ui.columns(self.num_columns, |cols| {
for (i, col) in cols.iter_mut().enumerate() {
col.label(format!("Column {} out of {}", i + 1, data.num_columns));
if i + 1 == data.num_columns && col.button("Delete this").clicked() {
data.num_columns -= 1;
col.label(format!("Column {} out of {}", i + 1, self.num_columns));
if i + 1 == self.num_columns && col.button("Delete this").clicked() {
self.num_columns -= 1;
}
}
});
@@ -140,7 +128,7 @@ impl View for MiscDemoWindow {
CollapsingHeader::new("Test box rendering")
.default_open(false)
.show(ui, |ui| data.box_painting.ui(ui));
.show(ui, |ui| self.box_painting.ui(ui));
CollapsingHeader::new("Resize")
.default_open(false)

View File

@@ -1,23 +1,16 @@
use std::sync::{Arc, RwLock};
use egui::{
emath::{RectTransform, Rot2},
vec2, Color32, Frame, Pos2, Rect, Sense, Stroke, Vec2,
};
pub struct MultiTouchData {
pub struct MultiTouch {
rotation: f32,
translation: Vec2,
zoom: f32,
last_touch_time: f64,
}
#[derive(Clone, Default)]
pub struct MultiTouch {
data: Arc<RwLock<MultiTouchData>>,
}
impl Default for MultiTouchData {
impl Default for MultiTouch {
fn default() -> Self {
Self {
rotation: 0.,
@@ -34,14 +27,13 @@ impl super::Demo for MultiTouch {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.default_size(vec2(512.0, 512.0))
.resizable(true)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
@@ -91,24 +83,22 @@ impl super::View for MultiTouch {
// color and width:
let mut stroke_width = 1.;
if let Some(multi_touch) = ui.ctx().multi_touch() {
let mut data = self.data.write().unwrap();
// This adjusts the current zoom factor and rotation angle according to the dynamic
// change (for the current frame) of the touch gesture:
data.zoom *= multi_touch.zoom_delta;
data.rotation += multi_touch.rotation_delta;
self.zoom *= multi_touch.zoom_delta;
self.rotation += multi_touch.rotation_delta;
// the translation we get from `multi_touch` needs to be scaled down to the
// normalized coordinates we use as the basis for painting:
data.translation += to_screen.inverse().scale() * multi_touch.translation_delta;
self.translation += to_screen.inverse().scale() * multi_touch.translation_delta;
// touch pressure will make the arrow thicker (not all touch devices support this):
stroke_width += 10. * multi_touch.force;
data.last_touch_time = ui.input(|i| i.time);
self.last_touch_time = ui.input(|i| i.time);
} else {
self.slowly_reset(ui);
}
let data = self.data.read().unwrap();
let zoom_and_rotate = data.zoom * Rot2::from_angle(data.rotation);
let arrow_start_offset = data.translation + zoom_and_rotate * vec2(-0.5, 0.5);
let zoom_and_rotate = self.zoom * Rot2::from_angle(self.rotation);
let arrow_start_offset = self.translation + zoom_and_rotate * vec2(-0.5, 0.5);
// Paints an arrow pointing from bottom-left (-0.5, 0.5) to top-right (0.5, -0.5), but
// scaled, rotated, and translated according to the current touch gesture:
@@ -128,8 +118,7 @@ impl MultiTouch {
// This has nothing to do with the touch gesture. It just smoothly brings the
// painted arrow back into its original position, for a nice visual effect:
let mut data = self.data.write().unwrap();
let time_since_last_touch = (ui.input(|i| i.time) - data.last_touch_time) as f32;
let time_since_last_touch = (ui.input(|i| i.time) - self.last_touch_time) as f32;
let delay = 0.5;
if time_since_last_touch < delay {
@@ -140,15 +129,15 @@ impl MultiTouch {
egui::remap_clamp(time_since_last_touch, delay..=1.0, 1.0..=0.0).powf(4.0);
if half_life <= 1e-3 {
data.zoom = 1.0;
data.rotation = 0.0;
data.translation = Vec2::ZERO;
self.zoom = 1.0;
self.rotation = 0.0;
self.translation = Vec2::ZERO;
} else {
let dt = ui.input(|i| i.unstable_dt);
let half_life_factor = (-(2_f32.ln()) / half_life * dt).exp();
data.zoom = 1. + ((data.zoom - 1.) * half_life_factor);
data.rotation *= half_life_factor;
data.translation *= half_life_factor;
self.zoom = 1. + ((self.zoom - 1.) * half_life_factor);
self.rotation *= half_life_factor;
self.translation *= half_life_factor;
ui.ctx().request_repaint();
}
}

View File

@@ -1,11 +1,9 @@
use std::sync::{Arc, RwLock};
use egui::epaint::{CubicBezierShape, PathShape, QuadraticBezierShape};
use egui::*;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct PaintBezierData {
pub struct PaintBezier {
/// Bézier curve degree, it can be 3, 4.
degree: usize,
@@ -24,14 +22,7 @@ pub struct PaintBezierData {
bounding_box_stroke: Stroke,
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[derive(Default, Clone)]
pub struct PaintBezier {
data: Arc<RwLock<PaintBezierData>>,
}
impl Default for PaintBezierData {
impl Default for PaintBezier {
fn default() -> Self {
Self {
degree: 4,
@@ -51,15 +42,14 @@ impl Default for PaintBezierData {
impl PaintBezier {
pub fn ui_control(&mut self, ui: &mut egui::Ui) {
let mut data = self.data.write().unwrap();
ui.collapsing("Colors", |ui| {
ui.horizontal(|ui| {
ui.label("Fill color:");
ui.color_edit_button_srgba(&mut data.fill);
ui.color_edit_button_srgba(&mut self.fill);
});
egui::stroke_ui(ui, &mut data.stroke, "Curve Stroke");
egui::stroke_ui(ui, &mut data.aux_stroke, "Auxiliary Stroke");
egui::stroke_ui(ui, &mut data.bounding_box_stroke, "Bounding Box Stroke");
egui::stroke_ui(ui, &mut self.stroke, "Curve Stroke");
egui::stroke_ui(ui, &mut self.aux_stroke, "Auxiliary Stroke");
egui::stroke_ui(ui, &mut self.bounding_box_stroke, "Bounding Box Stroke");
});
ui.collapsing("Global tessellation options", |ui| {
@@ -69,8 +59,8 @@ impl PaintBezier {
.tessellation_options_mut(|to| *to = tessellation_options);
});
ui.radio_value(&mut data.degree, 3, "Quadratic Bézier");
ui.radio_value(&mut data.degree, 4, "Cubic Bézier");
ui.radio_value(&mut self.degree, 3, "Quadratic Bézier");
ui.radio_value(&mut self.degree, 4, "Cubic Bézier");
ui.label("Move the points by dragging them.");
ui.small("Only convex curves can be accurately filled.");
}
@@ -85,14 +75,12 @@ impl PaintBezier {
);
let control_point_radius = 8.0;
let mut data = self.data.write().unwrap();
let data = &mut *data;
let control_point_shapes: Vec<Shape> = data
let control_point_shapes: Vec<Shape> = self
.control_points
.iter_mut()
.enumerate()
.take(data.degree)
.take(self.degree)
.map(|(i, point)| {
let size = Vec2::splat(2.0 * control_point_radius);
@@ -111,33 +99,33 @@ impl PaintBezier {
})
.collect();
let points_in_screen: Vec<Pos2> = data
let points_in_screen: Vec<Pos2> = self
.control_points
.iter()
.take(data.degree)
.take(self.degree)
.map(|p| to_screen * *p)
.collect();
match data.degree {
match self.degree {
3 => {
let points = points_in_screen.clone().try_into().unwrap();
let shape =
QuadraticBezierShape::from_points_stroke(points, true, data.fill, data.stroke);
QuadraticBezierShape::from_points_stroke(points, true, self.fill, self.stroke);
painter.add(epaint::RectShape::stroke(
shape.visual_bounding_rect(),
0.0,
data.bounding_box_stroke,
self.bounding_box_stroke,
));
painter.add(shape);
}
4 => {
let points = points_in_screen.clone().try_into().unwrap();
let shape =
CubicBezierShape::from_points_stroke(points, true, data.fill, data.stroke);
CubicBezierShape::from_points_stroke(points, true, self.fill, self.stroke);
painter.add(epaint::RectShape::stroke(
shape.visual_bounding_rect(),
0.0,
data.bounding_box_stroke,
self.bounding_box_stroke,
));
painter.add(shape);
}
@@ -146,7 +134,7 @@ impl PaintBezier {
}
};
painter.add(PathShape::line(points_in_screen, data.aux_stroke));
painter.add(PathShape::line(points_in_screen, self.aux_stroke));
painter.extend(control_point_shapes);
response
@@ -159,14 +147,13 @@ impl super::Demo for PaintBezier {
}
fn show(&mut self, ctx: &Context, open: &mut bool) {
let clone = self.clone();
use super::View as _;
Window::new(self.name())
.open(open)
.vscroll(false)
.resizable(false)
.default_size([300.0, 350.0])
.show(ctx, move |ui| clone.clone().ui(ui));
.show(ctx, move |ui| self.ui(ui));
}
}

View File

@@ -1,22 +1,14 @@
use std::sync::{Arc, RwLock};
use egui::*;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct PaintingData {
pub struct Painting {
/// in 0-1 normalized coordinates
lines: Vec<Vec<Pos2>>,
stroke: Stroke,
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[derive(Default, Clone)]
pub struct Painting {
data: Arc<RwLock<PaintingData>>,
}
impl Default for PaintingData {
impl Default for Painting {
fn default() -> Self {
Self {
lines: Default::default(),
@@ -27,12 +19,11 @@ impl Default for PaintingData {
impl Painting {
pub fn ui_control(&mut self, ui: &mut egui::Ui) -> egui::Response {
let mut data = self.data.write().unwrap();
ui.horizontal(|ui| {
egui::stroke_ui(ui, &mut data.stroke, "Stroke");
egui::stroke_ui(ui, &mut self.stroke, "Stroke");
ui.separator();
if ui.button("Clear Painting").clicked() {
data.lines.clear();
self.lines.clear();
}
})
.response
@@ -48,13 +39,11 @@ impl Painting {
);
let from_screen = to_screen.inverse();
let mut data = self.data.write().unwrap();
if data.lines.is_empty() {
data.lines.push(vec![]);
if self.lines.is_empty() {
self.lines.push(vec![]);
}
let current_line = data.lines.last_mut().unwrap();
let current_line = self.lines.last_mut().unwrap();
if let Some(pointer_pos) = response.interact_pointer_pos() {
let canvas_pos = from_screen * pointer_pos;
@@ -63,17 +52,17 @@ impl Painting {
response.mark_changed();
}
} else if !current_line.is_empty() {
data.lines.push(vec![]);
self.lines.push(vec![]);
response.mark_changed();
}
let shapes = data
let shapes = self
.lines
.iter()
.filter(|line| line.len() >= 2)
.map(|line| {
let points: Vec<Pos2> = line.iter().map(|p| to_screen * *p).collect();
egui::Shape::line(points, data.stroke)
egui::Shape::line(points, self.stroke)
});
painter.extend(shapes);
@@ -88,13 +77,12 @@ impl super::Demo for Painting {
}
fn show(&mut self, ctx: &Context, open: &mut bool) {
let clone = self.clone();
use super::View as _;
Window::new(self.name())
.open(open)
.default_size(vec2(512.0, 512.0))
.vscroll(false)
.show(ctx, move |ui| clone.clone().ui(ui));
.show(ctx, move |ui| self.ui(ui));
}
}

View File

@@ -1,6 +1,5 @@
use std::f64::consts::TAU;
use std::ops::RangeInclusive;
use std::sync::{Arc, RwLock};
use egui::plot::{AxisBools, GridInput, GridMark, PlotResponse};
use egui::*;
@@ -31,9 +30,8 @@ impl Default for Panel {
}
// ----------------------------------------------------------------------------
#[derive(PartialEq, Default)]
pub struct PlotDemoData {
#[derive(Default, PartialEq)]
pub struct PlotDemo {
line_demo: LineDemo,
marker_demo: MarkerDemo,
legend_demo: LegendDemo,
@@ -45,30 +43,18 @@ pub struct PlotDemoData {
open_panel: Panel,
}
#[derive(Default, Clone)]
pub struct PlotDemo {
data: Arc<RwLock<PlotDemoData>>,
}
impl PartialEq for PlotDemo {
fn eq(&self, other: &Self) -> bool {
*self.data.read().unwrap() == *other.data.read().unwrap()
}
}
impl super::Demo for PlotDemo {
fn name(&self) -> &'static str {
"🗠 Plot"
}
fn show(&mut self, ctx: &Context, open: &mut bool) {
let clone = self.clone();
use super::View as _;
Window::new(self.name())
.open(open)
.default_size(vec2(400.0, 400.0))
.vscroll(false)
.show(ctx, move |ui| clone.clone().ui(ui));
.show(ctx, |ui| self.ui(ui));
}
}
@@ -90,44 +76,43 @@ impl super::View for PlotDemo {
ui.add(crate::egui_github_link_file!());
});
});
let mut data = self.data.write().unwrap();
ui.separator();
ui.horizontal(|ui| {
ui.selectable_value(&mut data.open_panel, Panel::Lines, "Lines");
ui.selectable_value(&mut data.open_panel, Panel::Markers, "Markers");
ui.selectable_value(&mut data.open_panel, Panel::Legend, "Legend");
ui.selectable_value(&mut data.open_panel, Panel::Charts, "Charts");
ui.selectable_value(&mut data.open_panel, Panel::Items, "Items");
ui.selectable_value(&mut data.open_panel, Panel::Interaction, "Interaction");
ui.selectable_value(&mut data.open_panel, Panel::CustomAxes, "Custom Axes");
ui.selectable_value(&mut data.open_panel, Panel::LinkedAxes, "Linked Axes");
ui.selectable_value(&mut self.open_panel, Panel::Lines, "Lines");
ui.selectable_value(&mut self.open_panel, Panel::Markers, "Markers");
ui.selectable_value(&mut self.open_panel, Panel::Legend, "Legend");
ui.selectable_value(&mut self.open_panel, Panel::Charts, "Charts");
ui.selectable_value(&mut self.open_panel, Panel::Items, "Items");
ui.selectable_value(&mut self.open_panel, Panel::Interaction, "Interaction");
ui.selectable_value(&mut self.open_panel, Panel::CustomAxes, "Custom Axes");
ui.selectable_value(&mut self.open_panel, Panel::LinkedAxes, "Linked Axes");
});
ui.separator();
match data.open_panel {
match self.open_panel {
Panel::Lines => {
data.line_demo.ui(ui);
self.line_demo.ui(ui);
}
Panel::Markers => {
data.marker_demo.ui(ui);
self.marker_demo.ui(ui);
}
Panel::Legend => {
data.legend_demo.ui(ui);
self.legend_demo.ui(ui);
}
Panel::Charts => {
data.charts_demo.ui(ui);
self.charts_demo.ui(ui);
}
Panel::Items => {
data.items_demo.ui(ui);
self.items_demo.ui(ui);
}
Panel::Interaction => {
data.interaction_demo.ui(ui);
self.interaction_demo.ui(ui);
}
Panel::CustomAxes => {
data.custom_axes_demo.ui(ui);
self.custom_axes_demo.ui(ui);
}
Panel::LinkedAxes => {
data.linked_axes_demo.ui(ui);
self.linked_axes_demo.ui(ui);
}
}
}

View File

@@ -1,5 +1,3 @@
use std::sync::{Arc, RwLock};
use egui::*;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
@@ -21,64 +19,49 @@ impl Default for ScrollDemo {
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[derive(Default, PartialEq)]
pub struct ScrollingData {
pub struct Scrolling {
demo: ScrollDemo,
scroll_to: ScrollTo,
scroll_stick_to: ScrollStickTo,
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[derive(Default, Clone)]
pub struct Scrolling {
data: Arc<RwLock<ScrollingData>>,
}
impl PartialEq for Scrolling {
fn eq(&self, other: &Self) -> bool {
*self.data.read().unwrap() == *other.data.read().unwrap()
}
}
impl super::Demo for Scrolling {
fn name(&self) -> &'static str {
"↕ Scrolling"
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.resizable(false)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
impl super::View for Scrolling {
fn ui(&mut self, ui: &mut Ui) {
let mut data = self.data.write().unwrap();
ui.horizontal(|ui| {
ui.selectable_value(&mut data.demo, ScrollDemo::ScrollTo, "Scroll to");
ui.selectable_value(&mut self.demo, ScrollDemo::ScrollTo, "Scroll to");
ui.selectable_value(
&mut data.demo,
&mut self.demo,
ScrollDemo::ManyLines,
"Scroll a lot of lines",
);
ui.selectable_value(
&mut data.demo,
&mut self.demo,
ScrollDemo::LargeCanvas,
"Scroll a large canvas",
);
ui.selectable_value(&mut data.demo, ScrollDemo::StickToEnd, "Stick to end");
ui.selectable_value(&mut data.demo, ScrollDemo::Bidirectional, "Bidirectional");
ui.selectable_value(&mut self.demo, ScrollDemo::StickToEnd, "Stick to end");
ui.selectable_value(&mut self.demo, ScrollDemo::Bidirectional, "Bidirectional");
});
ui.separator();
match data.demo {
match self.demo {
ScrollDemo::ScrollTo => {
data.scroll_to.ui(ui);
self.scroll_to.ui(ui);
}
ScrollDemo::ManyLines => {
huge_content_lines(ui);
@@ -87,7 +70,7 @@ impl super::View for Scrolling {
huge_content_painter(ui);
}
ScrollDemo::StickToEnd => {
data.scroll_stick_to.ui(ui);
self.scroll_stick_to.ui(ui);
}
ScrollDemo::Bidirectional => {
egui::ScrollArea::both().show(ui, |ui| {

View File

@@ -1,14 +1,11 @@
use egui::*;
use std::{
f64::INFINITY,
sync::{Arc, RwLock},
};
use std::f64::INFINITY;
/// Showcase sliders
#[derive(PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct SlidersData {
pub struct Sliders {
pub min: f64,
pub max: f64,
pub logarithmic: bool,
@@ -22,20 +19,7 @@ pub struct SlidersData {
pub trailing_fill: bool,
}
#[derive(Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct Sliders {
pub data: Arc<RwLock<SlidersData>>,
}
impl PartialEq for Sliders {
fn eq(&self, other: &Self) -> bool {
*self.data.read().unwrap() == *other.data.read().unwrap()
}
}
impl Default for SlidersData {
impl Default for Sliders {
fn default() -> Self {
Self {
min: 0.0,
@@ -59,13 +43,12 @@ impl super::Demo for Sliders {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.resizable(false)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
@@ -73,7 +56,7 @@ impl super::Demo for Sliders {
impl super::View for Sliders {
fn ui(&mut self, ui: &mut Ui) {
{
let SlidersData {
let Sliders {
min,
max,
logarithmic,
@@ -85,7 +68,7 @@ impl super::View for Sliders {
vertical,
value,
trailing_fill,
} = &mut *self.data.write().unwrap();
} = self;
ui.label("You can click a slider value to edit it with the keyboard.");
@@ -138,7 +121,7 @@ impl super::View for Sliders {
);
if ui.button("Assign PI").clicked() {
self.data.write().unwrap().value = std::f64::consts::PI;
self.value = std::f64::consts::PI;
}
}

View File

@@ -1,5 +1,3 @@
use std::sync::{Arc, RwLock};
#[derive(PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
enum DemoType {
@@ -8,8 +6,9 @@ enum DemoType {
ManyHeterogenous,
}
/// Shows off a table with dynamic layout
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct TableDemoData {
pub struct TableDemo {
demo: DemoType,
striped: bool,
resizable: bool,
@@ -18,14 +17,7 @@ pub struct TableDemoData {
scroll_to_row: Option<usize>,
}
/// Shows off a table with dynamic layout
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Default)]
pub struct TableDemo {
data: Arc<RwLock<TableDemoData>>,
}
impl Default for TableDemoData {
impl Default for TableDemo {
fn default() -> Self {
Self {
demo: DemoType::Manual,
@@ -44,14 +36,13 @@ impl super::Demo for TableDemo {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.resizable(true)
.default_width(400.0)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
@@ -61,48 +52,47 @@ const NUM_MANUAL_ROWS: usize = 20;
impl super::View for TableDemo {
fn ui(&mut self, ui: &mut egui::Ui) {
{
let mut data = self.data.write().unwrap();
ui.vertical(|ui| {
ui.horizontal(|ui| {
ui.checkbox(&mut data.striped, "Striped");
ui.checkbox(&mut data.resizable, "Resizable columns");
ui.checkbox(&mut self.striped, "Striped");
ui.checkbox(&mut self.resizable, "Resizable columns");
});
ui.label("Table type:");
ui.radio_value(&mut data.demo, DemoType::Manual, "Few, manual rows");
ui.radio_value(&mut self.demo, DemoType::Manual, "Few, manual rows");
ui.radio_value(
&mut data.demo,
&mut self.demo,
DemoType::ManyHomogeneous,
"Thousands of rows of same height",
);
ui.radio_value(
&mut data.demo,
&mut self.demo,
DemoType::ManyHeterogenous,
"Thousands of rows of differing heights",
);
if data.demo != DemoType::Manual {
if self.demo != DemoType::Manual {
ui.add(
egui::Slider::new(&mut data.num_rows, 0..=100_000)
egui::Slider::new(&mut self.num_rows, 0..=100_000)
.logarithmic(true)
.text("Num rows"),
);
}
{
let max_rows = if data.demo == DemoType::Manual {
let max_rows = if self.demo == DemoType::Manual {
NUM_MANUAL_ROWS
} else {
data.num_rows
self.num_rows
};
let slider_response = ui.add(
egui::Slider::new(&mut data.scroll_to_row_slider, 0..=max_rows)
egui::Slider::new(&mut self.scroll_to_row_slider, 0..=max_rows)
.logarithmic(true)
.text("Row to scroll to"),
);
if slider_response.changed() {
data.scroll_to_row = Some(data.scroll_to_row_slider);
self.scroll_to_row = Some(self.scroll_to_row_slider);
}
}
});
@@ -135,11 +125,10 @@ impl TableDemo {
use egui_extras::{Column, TableBuilder};
let text_height = egui::TextStyle::Body.resolve(ui.style()).size;
let mut data = self.data.write().unwrap();
let mut table = TableBuilder::new(ui)
.striped(data.striped)
.resizable(data.resizable)
.striped(self.striped)
.resizable(self.resizable)
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
.column(Column::auto())
.column(Column::initial(100.0).range(40.0..=300.0))
@@ -147,7 +136,7 @@ impl TableDemo {
.column(Column::remainder())
.min_scrolled_height(0.0);
if let Some(row_nr) = data.scroll_to_row.take() {
if let Some(row_nr) = self.scroll_to_row.take() {
table = table.scroll_to_row(row_nr, None);
}
@@ -166,7 +155,7 @@ impl TableDemo {
ui.strong("Content");
});
})
.body(|mut body| match data.demo {
.body(|mut body| match self.demo {
DemoType::Manual => {
for row_index in 0..NUM_MANUAL_ROWS {
let is_thick = thick_row(row_index);
@@ -193,7 +182,7 @@ impl TableDemo {
}
}
DemoType::ManyHomogeneous => {
body.rows(text_height, data.num_rows, |row_index, mut row| {
body.rows(text_height, self.num_rows, |row_index, mut row| {
row.col(|ui| {
ui.label(row_index.to_string());
});
@@ -219,7 +208,7 @@ impl TableDemo {
}
}
body.heterogeneous_rows(
(0..data.num_rows).map(row_thickness),
(0..self.num_rows).map(row_thickness),
|row_index, mut row| {
row.col(|ui| {
ui.label(row_index.to_string());

View File

@@ -97,13 +97,14 @@ enum WidgetType {
}
#[derive(Debug, PartialEq)]
pub struct ManualLayoutTestData {
pub struct ManualLayoutTest {
widget_offset: egui::Vec2,
widget_size: egui::Vec2,
widget_type: WidgetType,
text_edit_contents: String,
}
impl Default for ManualLayoutTestData {
impl Default for ManualLayoutTest {
fn default() -> Self {
Self {
widget_offset: egui::Vec2::splat(150.0),
@@ -114,30 +115,18 @@ impl Default for ManualLayoutTestData {
}
}
#[derive(Clone, Debug, Default)]
pub struct ManualLayoutTest {
data: Arc<RwLock<ManualLayoutTestData>>,
}
impl PartialEq for ManualLayoutTest {
fn eq(&self, other: &Self) -> bool {
*self.data.read().unwrap() == *other.data.read().unwrap()
}
}
impl super::Demo for ManualLayoutTest {
fn name(&self) -> &'static str {
"Manual Layout Test"
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.resizable(false)
.open(open)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
@@ -146,12 +135,12 @@ impl super::View for ManualLayoutTest {
fn ui(&mut self, ui: &mut egui::Ui) {
egui::reset_button(ui, self);
let ManualLayoutTestData {
let ManualLayoutTest {
widget_offset,
widget_size,
widget_type,
text_edit_contents,
} = &mut *self.data.write().unwrap();
} = self;
ui.horizontal(|ui| {
ui.label("Test widget:");
ui.radio_value(widget_type, WidgetType::Button, "Button");
@@ -192,7 +181,7 @@ impl super::View for ManualLayoutTest {
// ----------------------------------------------------------------------------
#[derive(PartialEq)]
pub struct TableTestData {
pub struct TableTest {
num_cols: usize,
num_rows: usize,
min_col_width: f32,
@@ -200,18 +189,7 @@ pub struct TableTestData {
text_length: usize,
}
#[derive(Default, Clone)]
pub struct TableTest {
data: Arc<RwLock<TableTestData>>,
}
impl PartialEq for TableTest {
fn eq(&self, other: &Self) -> bool {
*self.data.read().unwrap() == *other.data.read().unwrap()
}
}
impl Default for TableTestData {
impl Default for TableTest {
fn default() -> Self {
Self {
num_cols: 4,
@@ -229,12 +207,11 @@ impl super::Demo for TableTest {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
@@ -242,17 +219,16 @@ impl super::Demo for TableTest {
impl super::View for TableTest {
fn ui(&mut self, ui: &mut egui::Ui) {
{
let mut data = self.data.write().unwrap();
ui.add(
egui::Slider::new(&mut data.min_col_width, 0.0..=400.0)
egui::Slider::new(&mut self.min_col_width, 0.0..=400.0)
.text("Minimum column width"),
);
ui.add(
egui::Slider::new(&mut data.max_col_width, 0.0..=400.0)
egui::Slider::new(&mut self.max_col_width, 0.0..=400.0)
.text("Maximum column width"),
);
ui.add(egui::Slider::new(&mut data.num_cols, 0..=5).text("Columns"));
ui.add(egui::Slider::new(&mut data.num_rows, 0..=20).text("Rows"));
ui.add(egui::Slider::new(&mut self.num_cols, 0..=5).text("Columns"));
ui.add(egui::Slider::new(&mut self.num_rows, 0..=20).text("Rows"));
ui.separator();
@@ -263,11 +239,11 @@ impl super::View for TableTest {
egui::Grid::new("my_grid")
.striped(true)
.min_col_width(data.min_col_width)
.max_col_width(data.max_col_width)
.min_col_width(self.min_col_width)
.max_col_width(self.max_col_width)
.show(ui, |ui| {
for row in 0..data.num_rows {
for col in 0..data.num_cols {
for row in 0..self.num_rows {
for col in 0..self.num_cols {
if col == 0 {
ui.label(format!("row {}", row));
} else {
@@ -286,7 +262,7 @@ impl super::View for TableTest {
});
ui.separator();
ui.add(egui::Slider::new(&mut data.text_length, 1..=40).text("Text length"));
ui.add(egui::Slider::new(&mut self.text_length, 1..=40).text("Text length"));
egui::Grid::new("parent grid").striped(true).show(ui, |ui| {
ui.vertical(|ui| {
ui.label("Vertical nest1");
@@ -321,7 +297,7 @@ impl super::View for TableTest {
ui.end_row();
let mut dyn_text = String::from("O");
dyn_text.extend(std::iter::repeat('h').take(data.text_length));
dyn_text.extend(std::iter::repeat('h').take(self.text_length));
ui.label(dyn_text);
ui.label("Fifth row, second column");
ui.end_row();
@@ -338,9 +314,9 @@ impl super::View for TableTest {
// ----------------------------------------------------------------------------
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Default, Clone)]
#[derive(Default)]
pub struct InputTest {
info: Arc<RwLock<String>>,
info: String,
}
impl super::Demo for InputTest {
@@ -349,13 +325,12 @@ impl super::Demo for InputTest {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.resizable(false)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
@@ -401,10 +376,10 @@ impl super::View for InputTest {
}
}
if !new_info.is_empty() {
*self.info.write().unwrap() = new_info;
self.info = new_info;
}
ui.label(&*self.info.write().unwrap());
ui.label(&self.info);
}
}

View File

@@ -1,23 +1,14 @@
use std::sync::{Arc, RwLock};
/// Showcase [`TextEdit`].
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[derive(Clone)]
pub struct TextEdit {
pub text: Arc<RwLock<String>>,
}
impl PartialEq for TextEdit {
fn eq(&self, other: &Self) -> bool {
*self.text.read().unwrap() == *other.text.read().unwrap()
}
pub text: String,
}
impl Default for TextEdit {
fn default() -> Self {
Self {
text: Arc::new(RwLock::new("Edit this text".to_owned())),
text: "Edit this text".to_owned(),
}
}
}
@@ -28,13 +19,12 @@ impl super::Demo for TextEdit {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.resizable(false)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
@@ -42,7 +32,6 @@ impl super::Demo for TextEdit {
impl super::View for TextEdit {
fn ui(&mut self, ui: &mut egui::Ui) {
let Self { text } = self;
let text = &mut *text.write().unwrap();
ui.horizontal(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;

View File

@@ -1,5 +1,3 @@
use std::sync::{Arc, RwLock};
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
enum Enum {
@@ -8,8 +6,9 @@ enum Enum {
Third,
}
/// Shows off one example of each major type of widget.
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct WidgetGalleryData {
pub struct WidgetGallery {
enabled: bool,
visible: bool,
boolean: bool,
@@ -27,14 +26,7 @@ pub struct WidgetGalleryData {
texture: Option<egui::TextureHandle>,
}
/// Shows off one example of each major type of widget.
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Default)]
pub struct WidgetGallery {
data: Arc<RwLock<WidgetGalleryData>>,
}
impl Default for WidgetGalleryData {
impl Default for WidgetGallery {
fn default() -> Self {
Self {
enabled: true,
@@ -58,24 +50,21 @@ impl super::Demo for WidgetGallery {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let clone = self.clone();
egui::Window::new(self.name())
.open(open)
.resizable(true)
.default_width(280.0)
.show(ctx, move |ui| {
use super::View as _;
clone.clone().ui(ui);
self.ui(ui);
});
}
}
impl super::View for WidgetGallery {
fn ui(&mut self, ui: &mut egui::Ui) {
let enabled = self.data.read().unwrap().enabled;
let visible = self.data.read().unwrap().visible;
ui.add_enabled_ui(enabled, |ui| {
ui.set_visible(visible);
ui.add_enabled_ui(self.enabled, |ui| {
ui.set_visible(self.visible);
egui::Grid::new("my_grid")
.num_columns(2)
@@ -85,14 +74,13 @@ impl super::View for WidgetGallery {
self.gallery_grid_contents(ui);
});
});
let data = &mut *self.data.write().unwrap();
ui.separator();
ui.horizontal(|ui| {
ui.checkbox(&mut data.visible, "Visible")
ui.checkbox(&mut self.visible, "Visible")
.on_hover_text("Uncheck to hide all the widgets.");
if data.visible {
ui.checkbox(&mut data.enabled, "Interactive")
if self.visible {
ui.checkbox(&mut self.enabled, "Interactive")
.on_hover_text("Uncheck to inspect how the widgets look when disabled.");
}
});
@@ -111,7 +99,7 @@ impl super::View for WidgetGallery {
impl WidgetGallery {
fn gallery_grid_contents(&mut self, ui: &mut egui::Ui) {
let WidgetGalleryData {
let WidgetGallery {
enabled: _,
visible: _,
boolean,
@@ -123,7 +111,7 @@ impl WidgetGallery {
#[cfg(feature = "chrono")]
date,
texture,
} = &mut *self.data.write().unwrap();
} = self;
let texture: &egui::TextureHandle = texture.get_or_insert_with(|| {
ui.ctx()

View File

@@ -1,8 +1,6 @@
use std::sync::{Arc, RwLock};
#[derive(Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct WindowOptionsData {
pub struct WindowOptions {
title: String,
title_bar: bool,
closable: bool,
@@ -15,19 +13,8 @@ pub struct WindowOptionsData {
anchor: egui::Align2,
anchor_offset: egui::Vec2,
}
#[derive(Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct WindowOptions {
data: Arc<RwLock<WindowOptionsData>>,
}
impl PartialEq for WindowOptions {
fn eq(&self, other: &Self) -> bool {
*self.data.read().unwrap() == *other.data.read().unwrap()
}
}
impl Default for WindowOptionsData {
impl Default for WindowOptions {
fn default() -> Self {
Self {
title: "🗖 Window Options".to_owned(),
@@ -50,7 +37,7 @@ impl super::Demo for WindowOptions {
}
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
let WindowOptionsData {
let WindowOptions {
title,
title_bar,
closable,
@@ -61,7 +48,7 @@ impl super::Demo for WindowOptions {
anchored,
anchor,
anchor_offset,
} = self.data.read().unwrap().clone();
} = self.clone();
let enabled = ctx.input(|i| i.time) - disabled_time > 2.0;
if !enabled {
@@ -82,76 +69,70 @@ impl super::Demo for WindowOptions {
if anchored {
window = window.anchor(anchor, anchor_offset);
}
let clone = self.clone();
window.show(ctx, move |ui| {
let mut clone = clone.clone();
clone.ui(ui)
});
window.show(ctx, move |ui| self.ui(ui));
}
}
impl super::View for WindowOptions {
fn ui(&mut self, ui: &mut egui::Ui) {
{
let WindowOptionsData {
title,
title_bar,
closable,
collapsible,
resizable,
scroll2,
disabled_time: _,
anchored,
anchor,
anchor_offset,
} = &mut *self.data.write().unwrap();
ui.horizontal(|ui| {
ui.label("title:");
ui.text_edit_singleline(title);
});
let WindowOptions {
title,
title_bar,
closable,
collapsible,
resizable,
scroll2,
disabled_time: _,
anchored,
anchor,
anchor_offset,
} = self;
ui.horizontal(|ui| {
ui.label("title:");
ui.text_edit_singleline(title);
});
ui.horizontal(|ui| {
ui.group(|ui| {
ui.vertical(|ui| {
ui.checkbox(title_bar, "title_bar");
ui.checkbox(closable, "closable");
ui.checkbox(collapsible, "collapsible");
ui.checkbox(resizable, "resizable");
ui.checkbox(&mut scroll2[0], "hscroll");
ui.checkbox(&mut scroll2[1], "vscroll");
});
ui.horizontal(|ui| {
ui.group(|ui| {
ui.vertical(|ui| {
ui.checkbox(title_bar, "title_bar");
ui.checkbox(closable, "closable");
ui.checkbox(collapsible, "collapsible");
ui.checkbox(resizable, "resizable");
ui.checkbox(&mut scroll2[0], "hscroll");
ui.checkbox(&mut scroll2[1], "vscroll");
});
ui.group(|ui| {
ui.vertical(|ui| {
ui.checkbox(anchored, "anchored");
ui.set_enabled(*anchored);
ui.horizontal(|ui| {
ui.label("x:");
ui.selectable_value(&mut anchor[0], egui::Align::LEFT, "Left");
ui.selectable_value(&mut anchor[0], egui::Align::Center, "Center");
ui.selectable_value(&mut anchor[0], egui::Align::RIGHT, "Right");
});
ui.horizontal(|ui| {
ui.label("y:");
ui.selectable_value(&mut anchor[1], egui::Align::TOP, "Top");
ui.selectable_value(&mut anchor[1], egui::Align::Center, "Center");
ui.selectable_value(&mut anchor[1], egui::Align::BOTTOM, "Bottom");
});
ui.horizontal(|ui| {
ui.label("Offset:");
ui.add(egui::DragValue::new(&mut anchor_offset.x));
ui.add(egui::DragValue::new(&mut anchor_offset.y));
});
});
ui.group(|ui| {
ui.vertical(|ui| {
ui.checkbox(anchored, "anchored");
ui.set_enabled(*anchored);
ui.horizontal(|ui| {
ui.label("x:");
ui.selectable_value(&mut anchor[0], egui::Align::LEFT, "Left");
ui.selectable_value(&mut anchor[0], egui::Align::Center, "Center");
ui.selectable_value(&mut anchor[0], egui::Align::RIGHT, "Right");
});
ui.horizontal(|ui| {
ui.label("y:");
ui.selectable_value(&mut anchor[1], egui::Align::TOP, "Top");
ui.selectable_value(&mut anchor[1], egui::Align::Center, "Center");
ui.selectable_value(&mut anchor[1], egui::Align::BOTTOM, "Bottom");
});
ui.horizontal(|ui| {
ui.label("Offset:");
ui.add(egui::DragValue::new(&mut anchor_offset.x));
ui.add(egui::DragValue::new(&mut anchor_offset.y));
});
});
});
}
});
ui.separator();
ui.horizontal(|ui| {
if ui.button("Disable for 2 seconds").clicked() {
self.data.write().unwrap().disabled_time = ui.input(|i| i.time);
self.disabled_time = ui.input(|i| i.time);
}
egui::reset_button(ui, self);
ui.add(crate::egui_github_link_file!());