mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 06:10:06 -04:00
Choose your own font and size (#1154)
* Refactor text layout: don't need &Fonts in all functions * Replace indexing in Fonts with member function * Wrap Fonts in a Mutex * Remove mutex for Font::glyph_info_cache * Remove RwLock around Font::characters * Put FontsImpl and GalleyCache behind the same Mutex * Round font sizes to whole pixels before deduplicating them * Make TextStyle !Copy * Implement user-named TextStyle:s * round font size earlier * Cache fonts based on family and size * Move TextStyle into egui and Style * Remove body_text_style * Query graphics about max texture size and use that as font atlas size * Recreate texture atlas when it is getting full
This commit is contained in:
@@ -71,7 +71,7 @@ impl super::View for CodeEditor {
|
||||
ui.collapsing("Theme", |ui| {
|
||||
ui.group(|ui| {
|
||||
theme.ui(ui);
|
||||
theme.store_in_memory(ui.ctx());
|
||||
theme.clone().store_in_memory(ui.ctx());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -85,7 +85,7 @@ impl super::View for CodeEditor {
|
||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||
ui.add(
|
||||
egui::TextEdit::multiline(code)
|
||||
.text_style(egui::TextStyle::Monospace) // for cursor height
|
||||
.font(egui::TextStyle::Monospace) // for cursor height
|
||||
.code_editor()
|
||||
.desired_rows(10)
|
||||
.lock_focus(true)
|
||||
|
||||
@@ -98,7 +98,8 @@ impl CodeExample {
|
||||
);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
let indentation = 8.0 * ui.fonts()[egui::TextStyle::Monospace].glyph_width(' ');
|
||||
let font_id = egui::TextStyle::Monospace.resolve(ui.style());
|
||||
let indentation = 8.0 * ui.fonts().glyph_width(&font_id, ' ');
|
||||
let item_spacing = ui.spacing_mut().item_spacing;
|
||||
ui.add_space(indentation - item_spacing.x);
|
||||
|
||||
|
||||
@@ -2,15 +2,15 @@ use std::collections::BTreeMap;
|
||||
|
||||
pub struct FontBook {
|
||||
filter: String,
|
||||
text_style: egui::TextStyle,
|
||||
named_chars: BTreeMap<egui::TextStyle, BTreeMap<char, String>>,
|
||||
font_id: egui::FontId,
|
||||
named_chars: BTreeMap<egui::FontFamily, BTreeMap<char, String>>,
|
||||
}
|
||||
|
||||
impl Default for FontBook {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
filter: Default::default(),
|
||||
text_style: egui::TextStyle::Button,
|
||||
font_id: egui::FontId::proportional(20.0),
|
||||
named_chars: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ impl super::View for FontBook {
|
||||
ui.label(format!(
|
||||
"The selected font supports {} characters.",
|
||||
self.named_chars
|
||||
.get(&self.text_style)
|
||||
.get(&self.font_id.family)
|
||||
.map(|map| map.len())
|
||||
.unwrap_or_default()
|
||||
));
|
||||
@@ -51,13 +51,7 @@ impl super::View for FontBook {
|
||||
|
||||
ui.separator();
|
||||
|
||||
egui::ComboBox::from_label("Text style")
|
||||
.selected_text(format!("{:?}", self.text_style))
|
||||
.show_ui(ui, |ui| {
|
||||
for style in egui::TextStyle::all() {
|
||||
ui.selectable_value(&mut self.text_style, style, format!("{:?}", style));
|
||||
}
|
||||
});
|
||||
egui::introspection::font_id_ui(ui, &mut self.font_id);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Filter:");
|
||||
@@ -68,16 +62,11 @@ impl super::View for FontBook {
|
||||
}
|
||||
});
|
||||
|
||||
let text_style = self.text_style;
|
||||
let filter = &self.filter;
|
||||
let named_chars = self.named_chars.entry(text_style).or_insert_with(|| {
|
||||
ui.fonts()[text_style]
|
||||
.characters()
|
||||
.iter()
|
||||
.filter(|chr| !chr.is_whitespace() && !chr.is_ascii_control())
|
||||
.map(|&chr| (chr, char_name(chr)))
|
||||
.collect()
|
||||
});
|
||||
let named_chars = self
|
||||
.named_chars
|
||||
.entry(self.font_id.family.clone())
|
||||
.or_insert_with(|| available_characters(ui, self.font_id.family.clone()));
|
||||
|
||||
ui.separator();
|
||||
|
||||
@@ -88,12 +77,14 @@ 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()).text_style(text_style),
|
||||
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()).text_style(text_style));
|
||||
ui.label(
|
||||
egui::RichText::new(chr.to_string()).font(self.font_id.clone()),
|
||||
);
|
||||
ui.label(format!("{}\nU+{:X}\n\nClick to copy", name, chr as u32));
|
||||
};
|
||||
|
||||
@@ -107,6 +98,18 @@ impl super::View for FontBook {
|
||||
}
|
||||
}
|
||||
|
||||
fn available_characters(ui: &egui::Ui, family: egui::FontFamily) -> BTreeMap<char, String> {
|
||||
ui.fonts()
|
||||
.lock()
|
||||
.fonts
|
||||
.font(&egui::FontId::new(10.0, family)) // size is arbitrary for getting the characters
|
||||
.characters()
|
||||
.iter()
|
||||
.filter(|chr| !chr.is_whitespace() && !chr.is_ascii_control())
|
||||
.map(|&chr| (chr, char_name(chr)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn char_name(chr: char) -> String {
|
||||
special_char_name(chr)
|
||||
.map(|s| s.to_owned())
|
||||
|
||||
@@ -140,7 +140,7 @@ impl Widgets {
|
||||
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
// Trick so we don't have to add spaces in the text below:
|
||||
let width = ui.fonts()[TextStyle::Body].glyph_width(' ');
|
||||
let width = ui.fonts().glyph_width(&TextStyle::Body.resolve(ui.style()), ' ');
|
||||
ui.spacing_mut().item_spacing.x = width;
|
||||
|
||||
ui.label(RichText::new("Text can have").color(Color32::from_rgb(110, 255, 110)));
|
||||
@@ -418,7 +418,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"This is a demonstration of ",
|
||||
first_row_indentation,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: default_color,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -427,7 +426,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"the egui text layout engine. ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: strong_color,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -436,7 +434,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"It supports ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: default_color,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -445,7 +442,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"different ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: Color32::from_rgb(110, 255, 110),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -454,7 +450,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"colors, ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: Color32::from_rgb(128, 140, 255),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -463,7 +458,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"backgrounds, ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: default_color,
|
||||
background: Color32::from_rgb(128, 32, 32),
|
||||
..Default::default()
|
||||
@@ -473,7 +467,7 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"mixing ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Heading,
|
||||
font_id: FontId::proportional(20.0),
|
||||
color: default_color,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -482,7 +476,7 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"fonts, ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Monospace,
|
||||
font_id: FontId::monospace(14.0),
|
||||
color: default_color,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -491,7 +485,7 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"raised text, ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Small,
|
||||
font_id: FontId::proportional(8.0),
|
||||
color: default_color,
|
||||
valign: Align::TOP,
|
||||
..Default::default()
|
||||
@@ -501,7 +495,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"with ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: default_color,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -510,7 +503,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"underlining",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: default_color,
|
||||
underline: Stroke::new(1.0, Color32::LIGHT_BLUE),
|
||||
..Default::default()
|
||||
@@ -520,7 +512,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
" and ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: default_color,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -529,7 +520,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"strikethrough",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: default_color,
|
||||
strikethrough: Stroke::new(2.0, Color32::RED.linear_multiply(0.5)),
|
||||
..Default::default()
|
||||
@@ -539,7 +529,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
". Of course, ",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: default_color,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -548,7 +537,6 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
"you can",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Body,
|
||||
color: default_color,
|
||||
strikethrough: Stroke::new(1.0, strong_color),
|
||||
..Default::default()
|
||||
@@ -558,7 +546,7 @@ fn text_layout_ui(ui: &mut egui::Ui) {
|
||||
" mix these!",
|
||||
0.0,
|
||||
TextFormat {
|
||||
style: TextStyle::Small,
|
||||
font_id: FontId::proportional(8.0),
|
||||
color: Color32::LIGHT_BLUE,
|
||||
background: Color32::from_rgb(128, 0, 0),
|
||||
underline: Stroke::new(1.0, strong_color),
|
||||
|
||||
@@ -261,9 +261,10 @@ impl Widget for &mut LegendDemo {
|
||||
egui::Grid::new("settings").show(ui, |ui| {
|
||||
ui.label("Text style:");
|
||||
ui.horizontal(|ui| {
|
||||
TextStyle::all().for_each(|style| {
|
||||
ui.selectable_value(&mut config.text_style, style, format!("{:?}", style));
|
||||
});
|
||||
let all_text_styles = ui.style().text_styles();
|
||||
for style in all_text_styles {
|
||||
ui.selectable_value(&mut config.text_style, style.clone(), style.to_string());
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
@@ -284,7 +285,9 @@ impl Widget for &mut LegendDemo {
|
||||
ui.end_row();
|
||||
});
|
||||
|
||||
let legend_plot = Plot::new("legend_demo").legend(*config).data_aspect(1.0);
|
||||
let legend_plot = Plot::new("legend_demo")
|
||||
.legend(config.clone())
|
||||
.data_aspect(1.0);
|
||||
legend_plot
|
||||
.show(ui, |plot_ui| {
|
||||
plot_ui.line(LegendDemo::line_with_slope(0.5).name("lines"));
|
||||
|
||||
@@ -81,7 +81,7 @@ fn huge_content_lines(ui: &mut egui::Ui) {
|
||||
ui.add_space(4.0);
|
||||
|
||||
let text_style = TextStyle::Body;
|
||||
let row_height = ui.fonts()[text_style].row_height();
|
||||
let row_height = ui.text_style_height(&text_style);
|
||||
let num_rows = 10_000;
|
||||
ScrollArea::vertical().auto_shrink([false; 2]).show_rows(
|
||||
ui,
|
||||
@@ -101,8 +101,8 @@ fn huge_content_painter(ui: &mut egui::Ui) {
|
||||
ui.label("A lot of rows, but only the visible ones are painted, so performance is still good:");
|
||||
ui.add_space(4.0);
|
||||
|
||||
let text_style = TextStyle::Body;
|
||||
let row_height = ui.fonts()[text_style].row_height() + ui.spacing().item_spacing.y;
|
||||
let font_id = TextStyle::Body.resolve(ui.style());
|
||||
let row_height = ui.fonts().row_height(&font_id) + ui.spacing().item_spacing.y;
|
||||
let num_rows = 10_000;
|
||||
|
||||
ScrollArea::vertical()
|
||||
@@ -130,7 +130,7 @@ fn huge_content_painter(ui: &mut egui::Ui) {
|
||||
pos2(x, y),
|
||||
Align2::LEFT_TOP,
|
||||
text,
|
||||
text_style,
|
||||
font_id.clone(),
|
||||
ui.visuals().text_color(),
|
||||
);
|
||||
used_rect = used_rect.union(text_rect);
|
||||
@@ -265,7 +265,7 @@ impl super::View for ScrollStickTo {
|
||||
ui.add_space(4.0);
|
||||
|
||||
let text_style = TextStyle::Body;
|
||||
let row_height = ui.fonts()[text_style].row_height();
|
||||
let row_height = ui.text_style_height(&text_style);
|
||||
ScrollArea::vertical().stick_to_bottom().show_rows(
|
||||
ui,
|
||||
row_height,
|
||||
|
||||
@@ -216,7 +216,7 @@ fn selectable_text(ui: &mut egui::Ui, mut text: &str) {
|
||||
ui.add(
|
||||
egui::TextEdit::multiline(&mut text)
|
||||
.desired_width(f32::INFINITY)
|
||||
.text_style(egui::TextStyle::Monospace),
|
||||
.font(egui::TextStyle::Monospace),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ impl ColoredText {
|
||||
let mut text = self.0.text.as_str();
|
||||
ui.add(
|
||||
egui::TextEdit::multiline(&mut text)
|
||||
.text_style(egui::TextStyle::Monospace)
|
||||
.font(egui::TextStyle::Monospace)
|
||||
.desired_width(f32::INFINITY)
|
||||
.layouter(&mut layouter),
|
||||
);
|
||||
|
||||
@@ -88,7 +88,7 @@ impl EasyMarkEditor {
|
||||
|
||||
let response = if self.highlight_editor {
|
||||
let mut layouter = |ui: &egui::Ui, easymark: &str, wrap_width: f32| {
|
||||
let mut layout_job = highlighter.highlight(ui.visuals(), easymark);
|
||||
let mut layout_job = highlighter.highlight(ui.style(), easymark);
|
||||
layout_job.wrap_width = wrap_width;
|
||||
ui.fonts().layout_job(layout_job)
|
||||
};
|
||||
@@ -96,7 +96,7 @@ impl EasyMarkEditor {
|
||||
ui.add(
|
||||
egui::TextEdit::multiline(code)
|
||||
.desired_width(f32::INFINITY)
|
||||
.text_style(egui::TextStyle::Monospace) // for cursor height
|
||||
.font(egui::TextStyle::Monospace) // for cursor height
|
||||
.layouter(&mut layouter),
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -5,23 +5,23 @@ use crate::easy_mark::easy_mark_parser;
|
||||
/// In practice, the highlighter is fast enough not to need any caching.
|
||||
#[derive(Default)]
|
||||
pub struct MemoizedEasymarkHighlighter {
|
||||
visuals: egui::Visuals,
|
||||
style: egui::Style,
|
||||
code: String,
|
||||
output: egui::text::LayoutJob,
|
||||
}
|
||||
|
||||
impl MemoizedEasymarkHighlighter {
|
||||
pub fn highlight(&mut self, visuals: &egui::Visuals, code: &str) -> egui::text::LayoutJob {
|
||||
if (&self.visuals, self.code.as_str()) != (visuals, code) {
|
||||
self.visuals = visuals.clone();
|
||||
pub fn highlight(&mut self, egui_style: &egui::Style, code: &str) -> egui::text::LayoutJob {
|
||||
if (&self.style, self.code.as_str()) != (egui_style, code) {
|
||||
self.style = egui_style.clone();
|
||||
self.code = code.to_owned();
|
||||
self.output = highlight_easymark(visuals, code);
|
||||
self.output = highlight_easymark(egui_style, code);
|
||||
}
|
||||
self.output.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn highlight_easymark(visuals: &egui::Visuals, mut text: &str) -> egui::text::LayoutJob {
|
||||
pub fn highlight_easymark(egui_style: &egui::Style, mut text: &str) -> egui::text::LayoutJob {
|
||||
let mut job = egui::text::LayoutJob::default();
|
||||
let mut style = easy_mark_parser::Style::default();
|
||||
let mut start_of_line = true;
|
||||
@@ -33,7 +33,7 @@ pub fn highlight_easymark(visuals: &egui::Visuals, mut text: &str) -> egui::text
|
||||
&text[..end],
|
||||
0.0,
|
||||
format_from_style(
|
||||
visuals,
|
||||
egui_style,
|
||||
&easy_mark_parser::Style {
|
||||
code: true,
|
||||
..Default::default()
|
||||
@@ -50,7 +50,7 @@ pub fn highlight_easymark(visuals: &egui::Visuals, mut text: &str) -> egui::text
|
||||
let end = text[1..]
|
||||
.find(&['`', '\n'][..])
|
||||
.map_or_else(|| text.len(), |i| i + 2);
|
||||
job.append(&text[..end], 0.0, format_from_style(visuals, &style));
|
||||
job.append(&text[..end], 0.0, format_from_style(egui_style, &style));
|
||||
text = &text[end..];
|
||||
style.code = false;
|
||||
continue;
|
||||
@@ -77,7 +77,7 @@ pub fn highlight_easymark(visuals: &egui::Visuals, mut text: &str) -> egui::text
|
||||
skip = 1;
|
||||
if style.strong {
|
||||
// Include the character that i ending ths style:
|
||||
job.append(&text[..skip], 0.0, format_from_style(visuals, &style));
|
||||
job.append(&text[..skip], 0.0, format_from_style(egui_style, &style));
|
||||
text = &text[skip..];
|
||||
skip = 0;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ pub fn highlight_easymark(visuals: &egui::Visuals, mut text: &str) -> egui::text
|
||||
skip = 1;
|
||||
if style.small {
|
||||
// Include the character that i ending ths style:
|
||||
job.append(&text[..skip], 0.0, format_from_style(visuals, &style));
|
||||
job.append(&text[..skip], 0.0, format_from_style(egui_style, &style));
|
||||
text = &text[skip..];
|
||||
skip = 0;
|
||||
}
|
||||
@@ -95,7 +95,7 @@ pub fn highlight_easymark(visuals: &egui::Visuals, mut text: &str) -> egui::text
|
||||
skip = 1;
|
||||
if style.raised {
|
||||
// Include the character that i ending ths style:
|
||||
job.append(&text[..skip], 0.0, format_from_style(visuals, &style));
|
||||
job.append(&text[..skip], 0.0, format_from_style(egui_style, &style));
|
||||
text = &text[skip..];
|
||||
skip = 0;
|
||||
}
|
||||
@@ -114,12 +114,16 @@ pub fn highlight_easymark(visuals: &egui::Visuals, mut text: &str) -> egui::text
|
||||
.map_or_else(|| text.len(), |i| (skip + i).max(1));
|
||||
|
||||
if line_end <= end {
|
||||
job.append(&text[..line_end], 0.0, format_from_style(visuals, &style));
|
||||
job.append(
|
||||
&text[..line_end],
|
||||
0.0,
|
||||
format_from_style(egui_style, &style),
|
||||
);
|
||||
text = &text[line_end..];
|
||||
start_of_line = true;
|
||||
style = Default::default();
|
||||
} else {
|
||||
job.append(&text[..end], 0.0, format_from_style(visuals, &style));
|
||||
job.append(&text[..end], 0.0, format_from_style(egui_style, &style));
|
||||
text = &text[end..];
|
||||
start_of_line = false;
|
||||
}
|
||||
@@ -129,17 +133,17 @@ pub fn highlight_easymark(visuals: &egui::Visuals, mut text: &str) -> egui::text
|
||||
}
|
||||
|
||||
fn format_from_style(
|
||||
visuals: &egui::Visuals,
|
||||
egui_style: &egui::Style,
|
||||
emark_style: &easy_mark_parser::Style,
|
||||
) -> egui::text::TextFormat {
|
||||
use egui::{Align, Color32, Stroke, TextStyle};
|
||||
|
||||
let color = if emark_style.strong || emark_style.heading {
|
||||
visuals.strong_text_color()
|
||||
egui_style.visuals.strong_text_color()
|
||||
} else if emark_style.quoted {
|
||||
visuals.weak_text_color()
|
||||
egui_style.visuals.weak_text_color()
|
||||
} else {
|
||||
visuals.text_color()
|
||||
egui_style.visuals.text_color()
|
||||
};
|
||||
|
||||
let text_style = if emark_style.heading {
|
||||
@@ -153,7 +157,7 @@ fn format_from_style(
|
||||
};
|
||||
|
||||
let background = if emark_style.code {
|
||||
visuals.code_bg_color
|
||||
egui_style.visuals.code_bg_color
|
||||
} else {
|
||||
Color32::TRANSPARENT
|
||||
};
|
||||
@@ -177,7 +181,7 @@ fn format_from_style(
|
||||
};
|
||||
|
||||
egui::text::TextFormat {
|
||||
style: text_style,
|
||||
font_id: text_style.resolve(egui_style),
|
||||
color,
|
||||
background,
|
||||
italics: emark_style.italics,
|
||||
|
||||
@@ -18,7 +18,7 @@ pub fn easy_mark_it<'em>(ui: &mut Ui, items: impl Iterator<Item = easy_mark::Ite
|
||||
|
||||
ui.allocate_ui_with_layout(initial_size, layout, |ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
let row_height = (*ui.fonts())[TextStyle::Body].row_height();
|
||||
let row_height = ui.text_style_height(&TextStyle::Body);
|
||||
ui.set_row_height(row_height);
|
||||
|
||||
for item in items {
|
||||
@@ -28,7 +28,7 @@ pub fn easy_mark_it<'em>(ui: &mut Ui, items: impl Iterator<Item = easy_mark::Ite
|
||||
}
|
||||
|
||||
pub fn item_ui(ui: &mut Ui, item: easy_mark::Item<'_>) {
|
||||
let row_height = ui.fonts()[TextStyle::Body].row_height();
|
||||
let row_height = ui.text_style_height(&TextStyle::Body);
|
||||
let one_indent = row_height / 2.0;
|
||||
|
||||
match item {
|
||||
@@ -134,7 +134,7 @@ fn rich_text_from_style(text: &str, style: &easy_mark::Style) -> RichText {
|
||||
}
|
||||
|
||||
fn bullet_point(ui: &mut Ui, width: f32) -> Response {
|
||||
let row_height = ui.fonts()[TextStyle::Body].row_height();
|
||||
let row_height = ui.text_style_height(&TextStyle::Body);
|
||||
let (rect, response) = ui.allocate_exact_size(vec2(width, row_height), Sense::hover());
|
||||
ui.painter().circle_filled(
|
||||
rect.center(),
|
||||
@@ -145,7 +145,8 @@ fn bullet_point(ui: &mut Ui, width: f32) -> Response {
|
||||
}
|
||||
|
||||
fn numbered_point(ui: &mut Ui, width: f32, number: &str) -> Response {
|
||||
let row_height = ui.fonts()[TextStyle::Body].row_height();
|
||||
let font_id = TextStyle::Body.resolve(ui.style());
|
||||
let row_height = ui.fonts().row_height(&font_id);
|
||||
let (rect, response) = ui.allocate_exact_size(vec2(width, row_height), Sense::hover());
|
||||
let text = format!("{}.", number);
|
||||
let text_color = ui.visuals().strong_text_color();
|
||||
@@ -153,7 +154,7 @@ fn numbered_point(ui: &mut Ui, width: f32, number: &str) -> Response {
|
||||
rect.right_center(),
|
||||
Align2::RIGHT_CENTER,
|
||||
text,
|
||||
TextStyle::Body,
|
||||
font_id,
|
||||
text_color,
|
||||
);
|
||||
response
|
||||
|
||||
@@ -98,7 +98,7 @@ impl FrameHistory {
|
||||
pos2(rect.left(), y),
|
||||
egui::Align2::LEFT_BOTTOM,
|
||||
text,
|
||||
TextStyle::Monospace,
|
||||
TextStyle::Monospace.resolve(ui.style()),
|
||||
color,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ pub fn code_view_ui(ui: &mut egui::Ui, mut code: &str) {
|
||||
|
||||
ui.add(
|
||||
egui::TextEdit::multiline(&mut code)
|
||||
.text_style(egui::TextStyle::Monospace) // for cursor height
|
||||
.font(egui::TextStyle::Monospace) // for cursor height
|
||||
.code_editor()
|
||||
.desired_rows(1)
|
||||
.lock_focus(true)
|
||||
@@ -116,7 +116,7 @@ impl SyntectTheme {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Hash, PartialEq)]
|
||||
#[derive(Clone, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
pub struct CodeTheme {
|
||||
@@ -158,15 +158,15 @@ impl CodeTheme {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store_in_memory(&self, ctx: &egui::Context) {
|
||||
pub fn store_in_memory(self, ctx: &egui::Context) {
|
||||
if self.dark_mode {
|
||||
ctx.memory()
|
||||
.data
|
||||
.insert_persisted(egui::Id::new("dark"), *self);
|
||||
.insert_persisted(egui::Id::new("dark"), self);
|
||||
} else {
|
||||
ctx.memory()
|
||||
.data
|
||||
.insert_persisted(egui::Id::new("light"), *self);
|
||||
.insert_persisted(egui::Id::new("light"), self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,34 +201,34 @@ impl CodeTheme {
|
||||
#[cfg(not(feature = "syntect"))]
|
||||
impl CodeTheme {
|
||||
pub fn dark() -> Self {
|
||||
let text_style = egui::TextStyle::Monospace;
|
||||
let font_id = egui::FontId::monospace(12.0);
|
||||
use egui::{Color32, TextFormat};
|
||||
Self {
|
||||
dark_mode: true,
|
||||
formats: enum_map::enum_map![
|
||||
TokenType::Comment => TextFormat::simple(text_style, Color32::from_gray(120)),
|
||||
TokenType::Keyword => TextFormat::simple(text_style, Color32::from_rgb(255, 100, 100)),
|
||||
TokenType::Literal => TextFormat::simple(text_style, Color32::from_rgb(87, 165, 171)),
|
||||
TokenType::StringLiteral => TextFormat::simple(text_style, Color32::from_rgb(109, 147, 226)),
|
||||
TokenType::Punctuation => TextFormat::simple(text_style, Color32::LIGHT_GRAY),
|
||||
TokenType::Whitespace => TextFormat::simple(text_style, Color32::TRANSPARENT),
|
||||
TokenType::Comment => TextFormat::simple(font_id.clone(), Color32::from_gray(120)),
|
||||
TokenType::Keyword => TextFormat::simple(font_id.clone(), Color32::from_rgb(255, 100, 100)),
|
||||
TokenType::Literal => TextFormat::simple(font_id.clone(), Color32::from_rgb(87, 165, 171)),
|
||||
TokenType::StringLiteral => TextFormat::simple(font_id.clone(), Color32::from_rgb(109, 147, 226)),
|
||||
TokenType::Punctuation => TextFormat::simple(font_id.clone(), Color32::LIGHT_GRAY),
|
||||
TokenType::Whitespace => TextFormat::simple(font_id.clone(), Color32::TRANSPARENT),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn light() -> Self {
|
||||
let text_style = egui::TextStyle::Monospace;
|
||||
let font_id = egui::FontId::monospace(12.0);
|
||||
use egui::{Color32, TextFormat};
|
||||
Self {
|
||||
dark_mode: false,
|
||||
#[cfg(not(feature = "syntect"))]
|
||||
formats: enum_map::enum_map![
|
||||
TokenType::Comment => TextFormat::simple(text_style, Color32::GRAY),
|
||||
TokenType::Keyword => TextFormat::simple(text_style, Color32::from_rgb(235, 0, 0)),
|
||||
TokenType::Literal => TextFormat::simple(text_style, Color32::from_rgb(153, 134, 255)),
|
||||
TokenType::StringLiteral => TextFormat::simple(text_style, Color32::from_rgb(37, 203, 105)),
|
||||
TokenType::Punctuation => TextFormat::simple(text_style, Color32::DARK_GRAY),
|
||||
TokenType::Whitespace => TextFormat::simple(text_style, Color32::TRANSPARENT),
|
||||
TokenType::Comment => TextFormat::simple(font_id.clone(), Color32::GRAY),
|
||||
TokenType::Keyword => TextFormat::simple(font_id.clone(), Color32::from_rgb(235, 0, 0)),
|
||||
TokenType::Literal => TextFormat::simple(font_id.clone(), Color32::from_rgb(153, 134, 255)),
|
||||
TokenType::StringLiteral => TextFormat::simple(font_id.clone(), Color32::from_rgb(37, 203, 105)),
|
||||
TokenType::Punctuation => TextFormat::simple(font_id.clone(), Color32::DARK_GRAY),
|
||||
TokenType::Whitespace => TextFormat::simple(font_id.clone(), Color32::TRANSPARENT),
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -259,7 +259,7 @@ impl CodeTheme {
|
||||
// (TokenType::Whitespace, "whitespace"),
|
||||
] {
|
||||
let format = &mut self.formats[tt];
|
||||
ui.style_mut().override_text_style = Some(format.style);
|
||||
ui.style_mut().override_font_id = Some(format.font_id.clone());
|
||||
ui.visuals_mut().override_text_color = Some(format.color);
|
||||
ui.radio_value(&mut selected_tt, tt, tt_name);
|
||||
}
|
||||
@@ -325,7 +325,7 @@ impl Highligher {
|
||||
// Fallback:
|
||||
LayoutJob::simple(
|
||||
code.into(),
|
||||
egui::TextStyle::Monospace,
|
||||
egui::FontId::monospace(14.0),
|
||||
if theme.dark_mode {
|
||||
egui::Color32::LIGHT_GRAY
|
||||
} else {
|
||||
@@ -371,7 +371,7 @@ impl Highligher {
|
||||
leading_space: 0.0,
|
||||
byte_range: as_byte_range(text, range),
|
||||
format: TextFormat {
|
||||
style: egui::TextStyle::Monospace,
|
||||
font_id: egui::FontId::monospace(14.0),
|
||||
color: text_color,
|
||||
italics,
|
||||
underline,
|
||||
@@ -412,7 +412,7 @@ impl Highligher {
|
||||
while !text.is_empty() {
|
||||
if text.starts_with("//") {
|
||||
let end = text.find('\n').unwrap_or_else(|| text.len());
|
||||
job.append(&text[..end], 0.0, theme.formats[TokenType::Comment]);
|
||||
job.append(&text[..end], 0.0, theme.formats[TokenType::Comment].clone());
|
||||
text = &text[end..];
|
||||
} else if text.starts_with('"') {
|
||||
let end = text[1..]
|
||||
@@ -420,7 +420,11 @@ impl Highligher {
|
||||
.map(|i| i + 2)
|
||||
.or_else(|| text.find('\n'))
|
||||
.unwrap_or_else(|| text.len());
|
||||
job.append(&text[..end], 0.0, theme.formats[TokenType::StringLiteral]);
|
||||
job.append(
|
||||
&text[..end],
|
||||
0.0,
|
||||
theme.formats[TokenType::StringLiteral].clone(),
|
||||
);
|
||||
text = &text[end..];
|
||||
} else if text.starts_with(|c: char| c.is_ascii_alphanumeric()) {
|
||||
let end = text[1..]
|
||||
@@ -432,19 +436,27 @@ impl Highligher {
|
||||
} else {
|
||||
TokenType::Literal
|
||||
};
|
||||
job.append(word, 0.0, theme.formats[tt]);
|
||||
job.append(word, 0.0, theme.formats[tt].clone());
|
||||
text = &text[end..];
|
||||
} else if text.starts_with(|c: char| c.is_ascii_whitespace()) {
|
||||
let end = text[1..]
|
||||
.find(|c: char| !c.is_ascii_whitespace())
|
||||
.map_or_else(|| text.len(), |i| i + 1);
|
||||
job.append(&text[..end], 0.0, theme.formats[TokenType::Whitespace]);
|
||||
job.append(
|
||||
&text[..end],
|
||||
0.0,
|
||||
theme.formats[TokenType::Whitespace].clone(),
|
||||
);
|
||||
text = &text[end..];
|
||||
} else {
|
||||
let mut it = text.char_indices();
|
||||
it.next();
|
||||
let end = it.next().map_or(text.len(), |(idx, _chr)| idx);
|
||||
job.append(&text[..end], 0.0, theme.formats[TokenType::Punctuation]);
|
||||
job.append(
|
||||
&text[..end],
|
||||
0.0,
|
||||
theme.formats[TokenType::Punctuation].clone(),
|
||||
);
|
||||
text = &text[end..];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ impl WrapApp {
|
||||
screen_rect.center(),
|
||||
Align2::CENTER_CENTER,
|
||||
text,
|
||||
TextStyle::Heading,
|
||||
TextStyle::Heading.resolve(&ctx.style()),
|
||||
Color32::WHITE,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user