mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 06:40:06 -04:00
Use new type Estring to avoid cloning &'static str
`ui.label("static string")` is a very common use case,
and currently egui clones the string in these cases.
This PR introduces a new type:
``` rust
pub enum Estring {
Static(&'static str),
Owned(Arc<str>),
}
```
which is used everywhere text is needed, with
`impl Into<Estring>` in the API for e.g. `ui.label`.
This reduces the number of copies drastically and speeds up
the benchmark demo_with_tessellate__realistic by 17%.
This hurts the ergonomics of egui a bit, and this is a breaking change.
For instance, this used to work:
``` rust
fn my_label(ui: &mut egui::Ui, text: &str) {
ui.label(text);
}
```
This must now either be changed to
``` rust
fn my_label(ui: &mut egui::Ui, text: &str) {
ui.label(text.to_string());
}
```
(or the argument must be changed to either
`text: &'static str` or `text: String`)
This commit is contained in:
@@ -57,7 +57,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
ui.label("the quick brown fox jumps over the lazy dog");
|
||||
})
|
||||
});
|
||||
c.bench_function("label format!", |b| {
|
||||
c.bench_function("label String", |b| {
|
||||
b.iter(|| {
|
||||
ui.label("the quick brown fox jumps over the lazy dog".to_owned());
|
||||
})
|
||||
@@ -77,20 +77,16 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
b.iter(|| {
|
||||
use egui::epaint::text::{layout, LayoutJob};
|
||||
|
||||
let job = LayoutJob::simple(
|
||||
LOREM_IPSUM_LONG.to_owned(),
|
||||
egui::TextStyle::Body,
|
||||
color,
|
||||
wrap_width,
|
||||
);
|
||||
let job =
|
||||
LayoutJob::simple(LOREM_IPSUM_LONG, egui::TextStyle::Body, color, wrap_width);
|
||||
layout(&fonts, job.into())
|
||||
})
|
||||
});
|
||||
c.bench_function("text_layout_cached", |b| {
|
||||
b.iter(|| fonts.layout(LOREM_IPSUM_LONG.to_owned(), text_style, color, wrap_width))
|
||||
b.iter(|| fonts.layout(LOREM_IPSUM_LONG, text_style, color, wrap_width))
|
||||
});
|
||||
|
||||
let galley = fonts.layout(LOREM_IPSUM_LONG.to_owned(), text_style, color, wrap_width);
|
||||
let galley = fonts.layout(LOREM_IPSUM_LONG, text_style, color, wrap_width);
|
||||
let mut tessellator = egui::epaint::Tessellator::from_options(Default::default());
|
||||
let mut mesh = egui::epaint::Mesh::default();
|
||||
c.bench_function("tessellate_text", |b| {
|
||||
|
||||
@@ -262,7 +262,7 @@ impl ColorTest {
|
||||
&mut self,
|
||||
ui: &mut Ui,
|
||||
tex_allocator: &mut Option<&mut dyn epi::TextureAllocator>,
|
||||
label: &str,
|
||||
label: &'static str,
|
||||
bg_fill: Color32,
|
||||
gradient: &Gradient,
|
||||
) {
|
||||
@@ -284,7 +284,13 @@ impl ColorTest {
|
||||
}
|
||||
}
|
||||
|
||||
fn vertex_gradient(&mut self, ui: &mut Ui, label: &str, bg_fill: Color32, gradient: &Gradient) {
|
||||
fn vertex_gradient(
|
||||
&mut self,
|
||||
ui: &mut Ui,
|
||||
label: &'static str,
|
||||
bg_fill: Color32,
|
||||
gradient: &Gradient,
|
||||
) {
|
||||
if !self.vertex_gradients {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ impl MemoizedSyntaxHighlighter {
|
||||
.highlight(is_dark_mode, code, language)
|
||||
.unwrap_or_else(|| {
|
||||
LayoutJob::simple(
|
||||
code.into(),
|
||||
code.to_owned(),
|
||||
egui::TextStyle::Monospace,
|
||||
if is_dark_mode {
|
||||
egui::Color32::LIGHT_GRAY
|
||||
@@ -172,7 +172,7 @@ impl Highligher {
|
||||
use egui::text::{LayoutSection, TextFormat};
|
||||
|
||||
let mut job = LayoutJob {
|
||||
text: text.into(),
|
||||
text: text.to_owned().into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -226,7 +226,7 @@ impl Highligher {
|
||||
fn highlight(&self, is_dark_mode: bool, mut text: &str, _language: &str) -> Option<LayoutJob> {
|
||||
// Extremely simple syntax highlighter for when we compile without syntect
|
||||
|
||||
use egui::text::TextFormat;
|
||||
use egui::text::{LayoutJobBuilder, TextFormat};
|
||||
use egui::Color32;
|
||||
let monospace = egui::TextStyle::Monospace;
|
||||
|
||||
@@ -265,7 +265,7 @@ impl Highligher {
|
||||
},
|
||||
);
|
||||
|
||||
let mut job = LayoutJob::default();
|
||||
let mut job = LayoutJobBuilder::default();
|
||||
|
||||
while !text.is_empty() {
|
||||
if text.starts_with("//") {
|
||||
@@ -308,7 +308,7 @@ impl Highligher {
|
||||
}
|
||||
}
|
||||
|
||||
Some(job)
|
||||
Some(job.build())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,10 +90,12 @@ 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(chr).text_style(text_style).frame(false);
|
||||
let button = egui::Button::new(chr.to_string())
|
||||
.text_style(text_style)
|
||||
.frame(false);
|
||||
|
||||
let tooltip_ui = |ui: &mut egui::Ui| {
|
||||
ui.add(egui::Label::new(chr).text_style(text_style));
|
||||
ui.add(egui::Label::new(chr.to_string()).text_style(text_style));
|
||||
ui.label(format!("{}\nU+{:X}\n\nClick to copy", name, chr as u32));
|
||||
};
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ impl Tree {
|
||||
)
|
||||
}
|
||||
pub fn ui(&mut self, ui: &mut Ui) -> Action {
|
||||
self.1.ui(ui, 0, "root", &mut self.0)
|
||||
self.1.ui(ui, 0, "root".to_owned(), &mut self.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,16 +342,16 @@ impl SubTree {
|
||||
&mut self,
|
||||
ui: &mut Ui,
|
||||
depth: usize,
|
||||
name: &str,
|
||||
name: String,
|
||||
selected_name: &mut String,
|
||||
) -> Action {
|
||||
let response = CollapsingHeader::new(name)
|
||||
let response = CollapsingHeader::new(name.clone())
|
||||
.default_open(depth < 1)
|
||||
.selectable(true)
|
||||
.selected(selected_name.as_str() == name)
|
||||
.show(ui, |ui| self.children_ui(ui, name, depth, selected_name));
|
||||
.show(ui, |ui| self.children_ui(ui, &name, depth, selected_name));
|
||||
if response.header_response.clicked() {
|
||||
*selected_name = name.to_string();
|
||||
*selected_name = name;
|
||||
}
|
||||
response.body_returned.unwrap_or(Action::Keep)
|
||||
}
|
||||
@@ -379,7 +379,7 @@ impl SubTree {
|
||||
if tree.ui(
|
||||
ui,
|
||||
depth + 1,
|
||||
&format!("{}/{}", parent_name, i),
|
||||
format!("{}/{}", parent_name, i),
|
||||
selected_name,
|
||||
) == Action::Keep
|
||||
{
|
||||
@@ -401,9 +401,9 @@ impl SubTree {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
use egui::epaint::text::{LayoutJob, TextFormat};
|
||||
use egui::epaint::text::{LayoutJobBuilder, TextFormat};
|
||||
|
||||
let mut job = LayoutJob::default();
|
||||
let mut job = LayoutJobBuilder::default();
|
||||
|
||||
let first_row_indentation = 10.0;
|
||||
|
||||
@@ -565,6 +565,7 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
},
|
||||
);
|
||||
|
||||
let mut job = job.build();
|
||||
job.wrap_width = ui.available_width();
|
||||
|
||||
let galley = ui.fonts().layout_job(job);
|
||||
|
||||
@@ -241,7 +241,7 @@ fn example_plot() -> egui::plot::Plot {
|
||||
.data_aspect(1.0)
|
||||
}
|
||||
|
||||
fn doc_link_label<'a>(title: &'a str, search_term: &'a str) -> impl egui::Widget + 'a {
|
||||
fn doc_link_label(title: &'static str, search_term: &'static str) -> impl egui::Widget {
|
||||
let label = format!("{}:", title);
|
||||
let url = format!("https://docs.rs/egui?search={}", search_term);
|
||||
move |ui: &mut egui::Ui| {
|
||||
|
||||
@@ -132,10 +132,12 @@ impl epi::App for HttpApp {
|
||||
}
|
||||
Err(error) => {
|
||||
// This should only happen if the fetch API isn't available or something similar.
|
||||
ui.add(
|
||||
egui::Label::new(if error.is_empty() { "Error" } else { error })
|
||||
.text_color(egui::Color32::RED),
|
||||
);
|
||||
let error = if error.is_empty() {
|
||||
"Error".to_owned()
|
||||
} else {
|
||||
error.clone()
|
||||
};
|
||||
ui.add(egui::Label::new(error).text_color(egui::Color32::RED));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,7 +327,7 @@ impl ColoredText {
|
||||
use egui::text::{LayoutJob, LayoutSection, TextFormat};
|
||||
|
||||
let mut job = LayoutJob {
|
||||
text: text.into(),
|
||||
text: text.to_owned().into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ pub fn item_ui(ui: &mut Ui, item: easy_mark::Item<'_>) {
|
||||
}
|
||||
easy_mark::Item::Hyperlink(style, text, url) => {
|
||||
let label = label_from_style(text, &style);
|
||||
ui.add(Hyperlink::from_label_and_url(label, url));
|
||||
ui.add(Hyperlink::from_label_and_url(label, url.to_owned()));
|
||||
}
|
||||
|
||||
easy_mark::Item::Separator => {
|
||||
@@ -75,7 +75,7 @@ pub fn item_ui(ui: &mut Ui, item: easy_mark::Item<'_>) {
|
||||
}
|
||||
easy_mark::Item::CodeBlock(_language, code) => {
|
||||
let where_to_put_background = ui.painter().add(Shape::Noop);
|
||||
let mut rect = ui.monospace(code).rect;
|
||||
let mut rect = ui.monospace(code.to_owned()).rect;
|
||||
rect = rect.expand(1.0); // looks better
|
||||
rect.max.x = ui.max_rect().max.x;
|
||||
let code_bg_color = ui.visuals().code_bg_color;
|
||||
@@ -102,7 +102,7 @@ fn label_from_style(text: &str, style: &easy_mark::Style) -> Label {
|
||||
|
||||
let small = small || raised; // Raised text is also smaller
|
||||
|
||||
let mut label = Label::new(text);
|
||||
let mut label = Label::new(text.to_owned());
|
||||
if heading && !small {
|
||||
label = label.heading().strong();
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ impl WrapApp {
|
||||
|
||||
for (anchor, app) in self.apps.iter_mut() {
|
||||
if ui
|
||||
.selectable_label(self.selected_anchor == anchor, app.name())
|
||||
.selectable_label(self.selected_anchor == anchor, app.name().to_owned())
|
||||
.clicked()
|
||||
{
|
||||
self.selected_anchor = anchor.to_owned();
|
||||
|
||||
Reference in New Issue
Block a user