mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 04:40:03 -04:00
⚠️ Improved menu based on egui::Popup (#5716)
Continuation of #5713 **Silently breaking changes:** - Menus now close on click by default, this is configurable via `PopupCloseBehavior` **Additional additions:** - `Button::right_text` - `StyleModifier` This is a rewrite of the egui menus, with the following goals: - submenu buttons should work everywhere, in a popup, context menu, area, in some random Ui - remove the menu state from Ui - should work just like the previous menu - ~proper support for keyboard navigation~ - It's better now but requires further work to be perfect - support `PopupCloseBehavior` * Closes #4607 * [x] I have followed the instructions in the PR template
This commit is contained in:
@@ -1,94 +0,0 @@
|
||||
use egui::{ComboBox, Popup};
|
||||
|
||||
#[derive(Clone, Default, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct ContextMenus {}
|
||||
|
||||
impl crate::Demo for ContextMenus {
|
||||
fn name(&self) -> &'static str {
|
||||
"☰ Context Menus"
|
||||
}
|
||||
|
||||
fn show(&mut self, ctx: &egui::Context, open: &mut bool) {
|
||||
use crate::View;
|
||||
egui::Window::new(self.name())
|
||||
.vscroll(false)
|
||||
.resizable(false)
|
||||
.open(open)
|
||||
.show(ctx, |ui| self.ui(ui));
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::View for ContextMenus {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.menu_button("Click for menu", Self::nested_menus);
|
||||
|
||||
ui.button("Right-click for menu")
|
||||
.context_menu(Self::nested_menus);
|
||||
|
||||
if ui.ctx().is_context_menu_open() {
|
||||
ui.label("Context menu is open");
|
||||
} else {
|
||||
ui.label("Context menu is closed");
|
||||
}
|
||||
});
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
let response = ui.button("New menu");
|
||||
Popup::menu(&response).show(Self::nested_menus);
|
||||
|
||||
let response = ui.button("New context menu");
|
||||
Popup::context_menu(&response).show(Self::nested_menus);
|
||||
|
||||
ComboBox::new("Hi", "Hi").show_ui(ui, |ui| {
|
||||
_ = ui.selectable_label(false, "I have some long text that should be wrapped");
|
||||
_ = ui.selectable_label(false, "Short");
|
||||
_ = ui.selectable_label(false, "Medium length");
|
||||
});
|
||||
});
|
||||
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.add(crate::egui_github_link_file!());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ContextMenus {
|
||||
fn nested_menus(ui: &mut egui::Ui) {
|
||||
ui.set_max_width(200.0); // To make sure we wrap long text
|
||||
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
let _ = ui.button("Item");
|
||||
ui.menu_button("Recursive", Self::nested_menus)
|
||||
});
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
let _ = ui.button("Item");
|
||||
});
|
||||
let _ = ui.button("Item");
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
let _ = ui.button("Item1");
|
||||
let _ = ui.button("Item2");
|
||||
let _ = ui.button("Item3");
|
||||
let _ = ui.button("Item4");
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
let _ = ui.button("Very long text for this item that should be wrapped");
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use egui::{Context, Modifiers, ScrollArea, Ui};
|
||||
|
||||
use super::About;
|
||||
use crate::is_mobile;
|
||||
use crate::Demo;
|
||||
use crate::View;
|
||||
|
||||
use egui::containers::menu;
|
||||
use egui::style::StyleModifier;
|
||||
use egui::{Context, Modifiers, ScrollArea, Ui};
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct DemoGroup {
|
||||
@@ -65,7 +65,6 @@ impl Default for DemoGroups {
|
||||
Box::<super::paint_bezier::PaintBezier>::default(),
|
||||
Box::<super::code_editor::CodeEditor>::default(),
|
||||
Box::<super::code_example::CodeExample>::default(),
|
||||
Box::<super::context_menu::ContextMenus>::default(),
|
||||
Box::<super::dancing_strings::DancingStrings>::default(),
|
||||
Box::<super::drag_and_drop::DragAndDropDemo>::default(),
|
||||
Box::<super::extra_viewport::ExtraViewport>::default(),
|
||||
@@ -227,29 +226,27 @@ impl DemoWindows {
|
||||
|
||||
fn mobile_top_bar(&mut self, ctx: &Context) {
|
||||
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
||||
egui::menu::bar(ui, |ui| {
|
||||
let font_size = 16.5;
|
||||
menu::Bar::new()
|
||||
.config(menu::MenuConfig::new().style(StyleModifier::default()))
|
||||
.ui(ui, |ui| {
|
||||
let font_size = 16.5;
|
||||
|
||||
ui.menu_button(egui::RichText::new("⏷ demos").size(font_size), |ui| {
|
||||
ui.set_style(ui.ctx().style()); // ignore the "menu" style set by `menu_button`.
|
||||
self.demo_list_ui(ui);
|
||||
if ui.ui_contains_pointer() && ui.input(|i| i.pointer.any_click()) {
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
ui.menu_button(egui::RichText::new("⏷ demos").size(font_size), |ui| {
|
||||
self.demo_list_ui(ui);
|
||||
});
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
use egui::special_emojis::GITHUB;
|
||||
ui.hyperlink_to(
|
||||
egui::RichText::new("🦋").size(font_size),
|
||||
"https://bsky.app/profile/ernerfeldt.bsky.social",
|
||||
);
|
||||
ui.hyperlink_to(
|
||||
egui::RichText::new(GITHUB).size(font_size),
|
||||
"https://github.com/emilk/egui",
|
||||
);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
use egui::special_emojis::GITHUB;
|
||||
ui.hyperlink_to(
|
||||
egui::RichText::new("🦋").size(font_size),
|
||||
"https://bsky.app/profile/ernerfeldt.bsky.social",
|
||||
);
|
||||
ui.hyperlink_to(
|
||||
egui::RichText::new(GITHUB).size(font_size),
|
||||
"https://github.com/emilk/egui",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -282,7 +279,7 @@ impl DemoWindows {
|
||||
});
|
||||
|
||||
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
|
||||
egui::menu::bar(ui, |ui| {
|
||||
menu::Bar::new().ui(ui, |ui| {
|
||||
file_menu_button(ui);
|
||||
});
|
||||
});
|
||||
@@ -345,7 +342,6 @@ fn file_menu_button(ui: &mut Ui) {
|
||||
.clicked()
|
||||
{
|
||||
ui.ctx().memory_mut(|mem| mem.reset_areas());
|
||||
ui.close();
|
||||
}
|
||||
|
||||
if ui
|
||||
@@ -357,7 +353,6 @@ fn file_menu_button(ui: &mut Ui) {
|
||||
.clicked()
|
||||
{
|
||||
ui.ctx().memory_mut(|mem| *mem = Default::default());
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
pub mod about;
|
||||
pub mod code_editor;
|
||||
pub mod code_example;
|
||||
pub mod context_menu;
|
||||
pub mod dancing_strings;
|
||||
pub mod demo_app_windows;
|
||||
pub mod drag_and_drop;
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
use egui::{vec2, Align2, ComboBox, Frame, Id, Popup, PopupCloseBehavior, RectAlign, Tooltip, Ui};
|
||||
use crate::rust_view_ui;
|
||||
use egui::containers::menu::{MenuConfig, SubMenuButton};
|
||||
use egui::{
|
||||
include_image, Align, Align2, ComboBox, Frame, Id, Layout, Popup, PopupCloseBehavior,
|
||||
RectAlign, Tooltip, Ui, UiBuilder,
|
||||
};
|
||||
|
||||
/// Showcase [`Popup`].
|
||||
#[derive(Clone, PartialEq)]
|
||||
@@ -10,6 +15,7 @@ pub struct PopupsDemo {
|
||||
#[cfg_attr(feature = "serde", serde(skip))]
|
||||
close_behavior: PopupCloseBehavior,
|
||||
popup_open: bool,
|
||||
checked: bool,
|
||||
}
|
||||
|
||||
impl PopupsDemo {
|
||||
@@ -28,6 +34,7 @@ impl Default for PopupsDemo {
|
||||
gap: 4.0,
|
||||
close_behavior: PopupCloseBehavior::CloseOnClick,
|
||||
popup_open: false,
|
||||
checked: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,120 +57,70 @@ impl crate::Demo for PopupsDemo {
|
||||
}
|
||||
}
|
||||
|
||||
fn nested_menus(ui: &mut egui::Ui, checked: &mut bool) {
|
||||
ui.set_max_width(200.0); // To make sure we wrap long text
|
||||
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
ui.menu_button("Popups can have submenus", |ui| {
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
let _ = ui.button("Item");
|
||||
ui.menu_button("Recursive", |ui| nested_menus(ui, checked));
|
||||
});
|
||||
ui.menu_button("SubMenu", |ui| {
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
let _ = ui.button("Item");
|
||||
});
|
||||
let _ = ui.button("Item");
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
ui.menu_image_text_button(
|
||||
include_image!("../../data/icon.png"),
|
||||
"I have an icon!",
|
||||
|ui| {
|
||||
let _ = ui.button("Item1");
|
||||
let _ = ui.button("Item2");
|
||||
let _ = ui.button("Item3");
|
||||
let _ = ui.button("Item4");
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
},
|
||||
);
|
||||
let _ = ui.button("Very long text for this item that should be wrapped");
|
||||
SubMenuButton::new("Always CloseOnClickOutside")
|
||||
.config(MenuConfig::new().close_behavior(PopupCloseBehavior::CloseOnClickOutside))
|
||||
.ui(ui, |ui| {
|
||||
ui.checkbox(checked, "Checkbox");
|
||||
if ui.button("Open…").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
impl crate::View for PopupsDemo {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.style_mut().spacing.item_spacing.x = 0.0;
|
||||
let align_combobox = |ui: &mut Ui, label: &str, align: &mut Align2| {
|
||||
let aligns = [
|
||||
(Align2::LEFT_TOP, "Left top"),
|
||||
(Align2::LEFT_CENTER, "Left center"),
|
||||
(Align2::LEFT_BOTTOM, "Left bottom"),
|
||||
(Align2::CENTER_TOP, "Center top"),
|
||||
(Align2::CENTER_CENTER, "Center center"),
|
||||
(Align2::CENTER_BOTTOM, "Center bottom"),
|
||||
(Align2::RIGHT_TOP, "Right top"),
|
||||
(Align2::RIGHT_CENTER, "Right center"),
|
||||
(Align2::RIGHT_BOTTOM, "Right bottom"),
|
||||
];
|
||||
|
||||
ui.label(label);
|
||||
ComboBox::new(label, "")
|
||||
.selected_text(aligns.iter().find(|(a, _)| a == align).unwrap().1)
|
||||
.show_ui(ui, |ui| {
|
||||
for (align2, name) in &aligns {
|
||||
ui.selectable_value(align, *align2, *name);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ui.label("Align4(");
|
||||
align_combobox(ui, "parent: ", &mut self.align4.parent);
|
||||
ui.label(", ");
|
||||
align_combobox(ui, "child: ", &mut self.align4.child);
|
||||
ui.label(") ");
|
||||
|
||||
let presets = [
|
||||
(RectAlign::TOP_START, "Top start"),
|
||||
(RectAlign::TOP, "Top"),
|
||||
(RectAlign::TOP_END, "Top end"),
|
||||
(RectAlign::RIGHT_START, "Right start"),
|
||||
(RectAlign::RIGHT, "Right Center"),
|
||||
(RectAlign::RIGHT_END, "Right end"),
|
||||
(RectAlign::BOTTOM_START, "Bottom start"),
|
||||
(RectAlign::BOTTOM, "Bottom"),
|
||||
(RectAlign::BOTTOM_END, "Bottom end"),
|
||||
(RectAlign::LEFT_START, "Left start"),
|
||||
(RectAlign::LEFT, "Left"),
|
||||
(RectAlign::LEFT_END, "Left end"),
|
||||
];
|
||||
|
||||
ui.label(" Presets: ");
|
||||
|
||||
ComboBox::new("Preset", "")
|
||||
.selected_text(
|
||||
presets
|
||||
.iter()
|
||||
.find(|(a, _)| a == &self.align4)
|
||||
.map_or("Select", |(_, name)| *name),
|
||||
)
|
||||
.show_ui(ui, |ui| {
|
||||
for (align4, name) in &presets {
|
||||
ui.selectable_value(&mut self.align4, *align4, *name);
|
||||
}
|
||||
});
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Gap:");
|
||||
ui.add(egui::DragValue::new(&mut self.gap));
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Close behavior:");
|
||||
ui.selectable_value(
|
||||
&mut self.close_behavior,
|
||||
PopupCloseBehavior::CloseOnClick,
|
||||
"Close on click",
|
||||
)
|
||||
.on_hover_text("Closes when the user clicks anywhere (inside or outside)");
|
||||
ui.selectable_value(
|
||||
&mut self.close_behavior,
|
||||
PopupCloseBehavior::CloseOnClickOutside,
|
||||
"Close on click outside",
|
||||
)
|
||||
.on_hover_text("Closes when the user clicks outside the popup");
|
||||
ui.selectable_value(
|
||||
&mut self.close_behavior,
|
||||
PopupCloseBehavior::IgnoreClicks,
|
||||
"Ignore clicks",
|
||||
)
|
||||
.on_hover_text("Close only when the button is clicked again");
|
||||
});
|
||||
|
||||
ui.checkbox(&mut self.popup_open, "Show popup");
|
||||
|
||||
let response = Frame::group(ui.style())
|
||||
.inner_margin(vec2(0.0, 25.0))
|
||||
.show(ui, |ui| {
|
||||
ui.set_width(ui.available_width());
|
||||
ui.vertical_centered(|ui| ui.button("Click, right-click and hover me!"))
|
||||
.inner
|
||||
})
|
||||
.inner;
|
||||
|
||||
self.apply_options(Popup::menu(&response).id(Id::new("menu")))
|
||||
.show(|ui| {
|
||||
_ = ui.button("Menu item 1");
|
||||
_ = ui.button("Menu item 2");
|
||||
|
||||
if ui.button("I always close the menu").clicked() {
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
.show(|ui| nested_menus(ui, &mut self.checked));
|
||||
|
||||
self.apply_options(Popup::context_menu(&response).id(Id::new("context_menu")))
|
||||
.show(|ui| {
|
||||
_ = ui.button("Context menu item 1");
|
||||
_ = ui.button("Context menu item 2");
|
||||
});
|
||||
.show(|ui| nested_menus(ui, &mut self.checked));
|
||||
|
||||
if self.popup_open {
|
||||
self.apply_options(Popup::from_response(&response).id(Id::new("popup")))
|
||||
@@ -178,6 +135,148 @@ impl crate::View for PopupsDemo {
|
||||
ui.label("Tooltips are popups, too!");
|
||||
});
|
||||
|
||||
Frame::canvas(ui.style()).show(ui, |ui| {
|
||||
let mut reset_btn_ui = ui.new_child(
|
||||
UiBuilder::new()
|
||||
.max_rect(ui.max_rect())
|
||||
.layout(Layout::right_to_left(Align::Min)),
|
||||
);
|
||||
if reset_btn_ui
|
||||
.button("⟲")
|
||||
.on_hover_text("Reset to defaults")
|
||||
.clicked()
|
||||
{
|
||||
*self = Self::default();
|
||||
}
|
||||
|
||||
ui.set_width(ui.available_width());
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
let align_combobox = |ui: &mut Ui, label: &str, align: &mut Align2| {
|
||||
let aligns = [
|
||||
(Align2::LEFT_TOP, "LEFT_TOP"),
|
||||
(Align2::LEFT_CENTER, "LEFT_CENTER"),
|
||||
(Align2::LEFT_BOTTOM, "LEFT_BOTTOM"),
|
||||
(Align2::CENTER_TOP, "CENTER_TOP"),
|
||||
(Align2::CENTER_CENTER, "CENTER_CENTER"),
|
||||
(Align2::CENTER_BOTTOM, "CENTER_BOTTOM"),
|
||||
(Align2::RIGHT_TOP, "RIGHT_TOP"),
|
||||
(Align2::RIGHT_CENTER, "RIGHT_CENTER"),
|
||||
(Align2::RIGHT_BOTTOM, "RIGHT_BOTTOM"),
|
||||
];
|
||||
|
||||
ComboBox::new(label, "")
|
||||
.selected_text(aligns.iter().find(|(a, _)| a == align).unwrap().1)
|
||||
.show_ui(ui, |ui| {
|
||||
for (align2, name) in &aligns {
|
||||
ui.selectable_value(align, *align2, *name);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
rust_view_ui(ui, "let align = RectAlign {");
|
||||
ui.horizontal(|ui| {
|
||||
rust_view_ui(ui, " parent: Align2::");
|
||||
align_combobox(ui, "parent", &mut self.align4.parent);
|
||||
rust_view_ui(ui, ",");
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
rust_view_ui(ui, " child: Align2::");
|
||||
align_combobox(ui, "child", &mut self.align4.child);
|
||||
rust_view_ui(ui, ",");
|
||||
});
|
||||
rust_view_ui(ui, "};");
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
rust_view_ui(ui, "let align = RectAlign::");
|
||||
|
||||
let presets = [
|
||||
(RectAlign::TOP_START, "TOP_START"),
|
||||
(RectAlign::TOP, "TOP"),
|
||||
(RectAlign::TOP_END, "TOP_END"),
|
||||
(RectAlign::RIGHT_START, "RIGHT_START"),
|
||||
(RectAlign::RIGHT, "RIGHT"),
|
||||
(RectAlign::RIGHT_END, "RIGHT_END"),
|
||||
(RectAlign::BOTTOM_START, "BOTTOM_START"),
|
||||
(RectAlign::BOTTOM, "BOTTOM"),
|
||||
(RectAlign::BOTTOM_END, "BOTTOM_END"),
|
||||
(RectAlign::LEFT_START, "LEFT_START"),
|
||||
(RectAlign::LEFT, "LEFT"),
|
||||
(RectAlign::LEFT_END, "LEFT_END"),
|
||||
];
|
||||
|
||||
ComboBox::new("Preset", "")
|
||||
.selected_text(
|
||||
presets
|
||||
.iter()
|
||||
.find(|(a, _)| a == &self.align4)
|
||||
.map_or("<Select Preset>", |(_, name)| *name),
|
||||
)
|
||||
.show_ui(ui, |ui| {
|
||||
for (align4, name) in &presets {
|
||||
ui.selectable_value(&mut self.align4, *align4, *name);
|
||||
}
|
||||
});
|
||||
rust_view_ui(ui, ";");
|
||||
});
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
rust_view_ui(ui, "let gap = ");
|
||||
ui.add(egui::DragValue::new(&mut self.gap));
|
||||
rust_view_ui(ui, ";");
|
||||
});
|
||||
|
||||
rust_view_ui(ui, "let close_behavior");
|
||||
ui.horizontal(|ui| {
|
||||
rust_view_ui(ui, " = PopupCloseBehavior::");
|
||||
let close_behaviors = [
|
||||
(
|
||||
PopupCloseBehavior::CloseOnClick,
|
||||
"CloseOnClick",
|
||||
"Closes when the user clicks anywhere (inside or outside)",
|
||||
),
|
||||
(
|
||||
PopupCloseBehavior::CloseOnClickOutside,
|
||||
"CloseOnClickOutside",
|
||||
"Closes when the user clicks outside the popup",
|
||||
),
|
||||
(
|
||||
PopupCloseBehavior::IgnoreClicks,
|
||||
"IgnoreClicks",
|
||||
"Close only when the button is clicked again",
|
||||
),
|
||||
];
|
||||
ComboBox::new("Close behavior", "")
|
||||
.selected_text(
|
||||
close_behaviors
|
||||
.iter()
|
||||
.find_map(|(behavior, text, _)| {
|
||||
(behavior == &self.close_behavior).then_some(*text)
|
||||
})
|
||||
.unwrap(),
|
||||
)
|
||||
.show_ui(ui, |ui| {
|
||||
for (close_behavior, name, tooltip) in &close_behaviors {
|
||||
ui.selectable_value(&mut self.close_behavior, *close_behavior, *name)
|
||||
.on_hover_text(*tooltip);
|
||||
}
|
||||
});
|
||||
rust_view_ui(ui, ";");
|
||||
});
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
rust_view_ui(ui, "let popup_open = ");
|
||||
ui.checkbox(&mut self.popup_open, "");
|
||||
rust_view_ui(ui, ";");
|
||||
});
|
||||
ui.monospace("");
|
||||
rust_view_ui(ui, "let response = ui.button(\"Click me!\");");
|
||||
rust_view_ui(ui, "Popup::menu(&response)");
|
||||
rust_view_ui(ui, " .gap(gap).align(align)");
|
||||
rust_view_ui(ui, " .close_behavior(close_behavior)");
|
||||
rust_view_ui(ui, " .show(|ui| { /* menu contents */ });");
|
||||
});
|
||||
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.add(crate::egui_github_link_file!());
|
||||
});
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4806984f9c801a054cea80b89664293680abaa57cf0a95cf9682f111e3794fc1
|
||||
size 25080
|
||||
oid sha256:17dc2a2f98d4cc52f6c6337dcc2e40f22d7310a933de91bb60576b893926193c
|
||||
size 58674
|
||||
|
||||
Reference in New Issue
Block a user