demo: in font book, ask font what characters are supported
This replaces manual lists with a call to ab_glypgh::Font::codepoint_ids plus names from the unicode_names2 crate.
This commit is contained in:
parent
749c5cbdc8
commit
1363ac4a24
7 changed files with 215 additions and 3993 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -795,6 +795,7 @@ dependencies = [
|
||||||
"image",
|
"image",
|
||||||
"serde",
|
"serde",
|
||||||
"syntect",
|
"syntect",
|
||||||
|
"unicode_names2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2418,6 +2419,12 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode_names2"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87d6678d7916394abad0d4b19df4d3802e1fd84abd7d701f39b75ee71b9e8cf1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
|
|
@ -25,6 +25,7 @@ all-features = true
|
||||||
[dependencies]
|
[dependencies]
|
||||||
egui = { version = "0.12.0", path = "../egui", default-features = false }
|
egui = { version = "0.12.0", path = "../egui", default-features = false }
|
||||||
epi = { version = "0.12.0", path = "../epi" }
|
epi = { version = "0.12.0", path = "../epi" }
|
||||||
|
unicode_names2 = { version = "0.4.0", default-features = false }
|
||||||
|
|
||||||
# feature "http":
|
# feature "http":
|
||||||
image = { version = "0.23", default-features = false, features = ["jpeg", "png"], optional = true }
|
image = { version = "0.23", default-features = false, features = ["jpeg", "png"], optional = true }
|
||||||
|
|
|
@ -1,40 +1,17 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
pub struct FontBook {
|
pub struct FontBook {
|
||||||
standard: bool,
|
|
||||||
emojis: bool,
|
|
||||||
filter: String,
|
filter: String,
|
||||||
text_style: egui::TextStyle,
|
text_style: egui::TextStyle,
|
||||||
|
named_chars: BTreeMap<egui::TextStyle, BTreeMap<char, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FontBook {
|
impl Default for FontBook {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
standard: false,
|
|
||||||
emojis: true,
|
|
||||||
filter: Default::default(),
|
filter: Default::default(),
|
||||||
text_style: egui::TextStyle::Button,
|
text_style: egui::TextStyle::Button,
|
||||||
}
|
named_chars: Default::default(),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FontBook {
|
|
||||||
fn characters_ui(&self, ui: &mut egui::Ui, characters: &[(u32, char, &str)]) {
|
|
||||||
use egui::{Button, Label};
|
|
||||||
for &(_, chr, name) in characters {
|
|
||||||
if self.filter.is_empty()
|
|
||||||
|| name.contains(&self.filter)
|
|
||||||
|| self.filter == chr.to_string()
|
|
||||||
{
|
|
||||||
let button = Button::new(chr).text_style(self.text_style).frame(false);
|
|
||||||
|
|
||||||
let tooltip_ui = |ui: &mut egui::Ui| {
|
|
||||||
ui.add(Label::new(chr).text_style(self.text_style));
|
|
||||||
ui.label(format!("{}\nU+{:X}\n\nClick to copy", name, chr as u32));
|
|
||||||
};
|
|
||||||
|
|
||||||
if ui.add(button).on_hover_ui(tooltip_ui).clicked() {
|
|
||||||
ui.output().copied_text = chr.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,13 +31,12 @@ impl super::Demo for FontBook {
|
||||||
|
|
||||||
impl super::View for FontBook {
|
impl super::View for FontBook {
|
||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
use super::font_contents_emoji::FULL_EMOJI_LIST;
|
|
||||||
use super::font_contents_ubuntu::UBUNTU_FONT_CHARACTERS;
|
|
||||||
|
|
||||||
ui.label(format!(
|
ui.label(format!(
|
||||||
"The default egui fonts supports {} standard characters and {} emojis.",
|
"The selected font supports {} characters.",
|
||||||
UBUNTU_FONT_CHARACTERS.len(),
|
self.named_chars
|
||||||
FULL_EMOJI_LIST.len(),
|
.get(&self.text_style)
|
||||||
|
.map(|map| map.len())
|
||||||
|
.unwrap_or_default()
|
||||||
));
|
));
|
||||||
|
|
||||||
ui.horizontal_wrapped(|ui| {
|
ui.horizontal_wrapped(|ui| {
|
||||||
|
@ -86,12 +62,6 @@ impl super::View for FontBook {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.label("Show:");
|
|
||||||
ui.checkbox(&mut self.standard, "Standard");
|
|
||||||
ui.checkbox(&mut self.emojis, "Emojis");
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Filter:");
|
ui.label("Filter:");
|
||||||
ui.text_edit_singleline(&mut self.filter);
|
ui.text_edit_singleline(&mut self.filter);
|
||||||
|
@ -101,19 +71,180 @@ 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()
|
||||||
|
});
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
egui::ScrollArea::auto_sized().show(ui, |ui| {
|
egui::ScrollArea::auto_sized().show(ui, |ui| {
|
||||||
ui.horizontal_wrapped(|ui| {
|
ui.horizontal_wrapped(|ui| {
|
||||||
ui.spacing_mut().item_spacing = egui::Vec2::splat(2.0);
|
ui.spacing_mut().item_spacing = egui::Vec2::splat(2.0);
|
||||||
|
|
||||||
if self.standard {
|
for (&chr, name) in named_chars {
|
||||||
self.characters_ui(ui, UBUNTU_FONT_CHARACTERS);
|
if filter.is_empty() || name.contains(filter) || *filter == chr.to_string() {
|
||||||
}
|
let button = egui::Button::new(chr).text_style(text_style).frame(false);
|
||||||
if self.emojis {
|
|
||||||
self.characters_ui(ui, FULL_EMOJI_LIST);
|
let tooltip_ui = |ui: &mut egui::Ui| {
|
||||||
|
ui.add(egui::Label::new(chr).text_style(text_style));
|
||||||
|
ui.label(format!("{}\nU+{:X}\n\nClick to copy", name, chr as u32));
|
||||||
|
};
|
||||||
|
|
||||||
|
if ui.add(button).on_hover_ui(tooltip_ui).clicked() {
|
||||||
|
ui.output().copied_text = chr.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn char_name(chr: char) -> String {
|
||||||
|
unicode_names2::name(chr)
|
||||||
|
.map(|name| name.to_string().to_lowercase())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
match chr {
|
||||||
|
// Special private-use-area extensions found in `emoji-icon-font.ttf`:
|
||||||
|
// Private use area extensions:
|
||||||
|
'\u{FE4E5}' => "flag japan".to_owned(),
|
||||||
|
'\u{FE4E6}' => "flag usa".to_owned(),
|
||||||
|
'\u{FE4E7}' => "flag".to_owned(),
|
||||||
|
'\u{FE4E8}' => "flag".to_owned(),
|
||||||
|
'\u{FE4E9}' => "flag".to_owned(),
|
||||||
|
'\u{FE4EA}' => "flag great britain".to_owned(),
|
||||||
|
'\u{FE4EB}' => "flag".to_owned(),
|
||||||
|
'\u{FE4EC}' => "flag".to_owned(),
|
||||||
|
'\u{FE4ED}' => "flag".to_owned(),
|
||||||
|
'\u{FE4EE}' => "flag south korea".to_owned(),
|
||||||
|
'\u{FE82C}' => "number sign in square".to_owned(),
|
||||||
|
'\u{FE82E}' => "digit one in square".to_owned(),
|
||||||
|
'\u{FE82F}' => "digit two in square".to_owned(),
|
||||||
|
'\u{FE830}' => "digit three in square".to_owned(),
|
||||||
|
'\u{FE831}' => "digit four in square".to_owned(),
|
||||||
|
'\u{FE832}' => "digit five in square".to_owned(),
|
||||||
|
'\u{FE833}' => "digit six in square".to_owned(),
|
||||||
|
'\u{FE834}' => "digit seven in square".to_owned(),
|
||||||
|
'\u{FE835}' => "digit eight in square".to_owned(),
|
||||||
|
'\u{FE836}' => "digit nine in square".to_owned(),
|
||||||
|
'\u{FE837}' => "digit zero in square".to_owned(),
|
||||||
|
|
||||||
|
// Special private-use-area extensions found in `emoji-icon-font.ttf`:
|
||||||
|
// Web services / operating systems / browsers
|
||||||
|
'\u{E600}' => "web-dribbble".to_owned(),
|
||||||
|
'\u{E601}' => "web-stackoverflow".to_owned(),
|
||||||
|
'\u{E602}' => "web-vimeo".to_owned(),
|
||||||
|
'\u{E603}' => "web-twitter".to_owned(),
|
||||||
|
'\u{E604}' => "web-facebook".to_owned(),
|
||||||
|
'\u{E605}' => "web-googleplus".to_owned(),
|
||||||
|
'\u{E606}' => "web-pinterest".to_owned(),
|
||||||
|
'\u{E607}' => "web-tumblr".to_owned(),
|
||||||
|
'\u{E608}' => "web-linkedin".to_owned(),
|
||||||
|
'\u{E60A}' => "web-stumbleupon".to_owned(),
|
||||||
|
'\u{E60B}' => "web-lastfm".to_owned(),
|
||||||
|
'\u{E60C}' => "web-rdio".to_owned(),
|
||||||
|
'\u{E60D}' => "web-spotify".to_owned(),
|
||||||
|
'\u{E60E}' => "web-qq".to_owned(),
|
||||||
|
'\u{E60F}' => "web-instagram".to_owned(),
|
||||||
|
'\u{E610}' => "web-dropbox".to_owned(),
|
||||||
|
'\u{E611}' => "web-evernote".to_owned(),
|
||||||
|
'\u{E612}' => "web-flattr".to_owned(),
|
||||||
|
'\u{E613}' => "web-skype".to_owned(),
|
||||||
|
'\u{E614}' => "web-renren".to_owned(),
|
||||||
|
'\u{E615}' => "web-sina-weibo".to_owned(),
|
||||||
|
'\u{E616}' => "web-paypal".to_owned(),
|
||||||
|
'\u{E617}' => "web-picasa".to_owned(),
|
||||||
|
'\u{E618}' => "os-android".to_owned(),
|
||||||
|
'\u{E619}' => "web-mixi".to_owned(),
|
||||||
|
'\u{E61A}' => "web-behance".to_owned(),
|
||||||
|
'\u{E61B}' => "web-circles".to_owned(),
|
||||||
|
'\u{E61C}' => "web-vk".to_owned(),
|
||||||
|
'\u{E61D}' => "web-smashing".to_owned(),
|
||||||
|
'\u{E61E}' => "web-forrst".to_owned(),
|
||||||
|
'\u{E61F}' => "os-windows".to_owned(),
|
||||||
|
'\u{E620}' => "web-flickr".to_owned(),
|
||||||
|
'\u{E621}' => "web-picassa".to_owned(),
|
||||||
|
'\u{E622}' => "web-deviantart".to_owned(),
|
||||||
|
'\u{E623}' => "web-steam".to_owned(),
|
||||||
|
'\u{E624}' => "web-github".to_owned(),
|
||||||
|
'\u{E625}' => "web-git".to_owned(),
|
||||||
|
'\u{E626}' => "web-blogger".to_owned(),
|
||||||
|
'\u{E627}' => "web-soundcloud".to_owned(),
|
||||||
|
'\u{E628}' => "web-reddit".to_owned(),
|
||||||
|
'\u{E629}' => "web-delicious".to_owned(),
|
||||||
|
'\u{E62A}' => "browser-chrome".to_owned(),
|
||||||
|
'\u{E62B}' => "browser-firefox".to_owned(),
|
||||||
|
'\u{E62C}' => "browser-ie".to_owned(),
|
||||||
|
'\u{E62D}' => "browser-opera".to_owned(),
|
||||||
|
'\u{E62E}' => "browser-safari".to_owned(),
|
||||||
|
'\u{E62F}' => "web-google-drive".to_owned(),
|
||||||
|
'\u{E630}' => "web-wordpress".to_owned(),
|
||||||
|
'\u{E631}' => "web-joomla".to_owned(),
|
||||||
|
'\u{E632}' => "lastfm".to_owned(),
|
||||||
|
'\u{E633}' => "web-foursquare".to_owned(),
|
||||||
|
'\u{E634}' => "web-yelp".to_owned(),
|
||||||
|
'\u{E635}' => "web-drupal".to_owned(),
|
||||||
|
'\u{E636}' => "youtube".to_owned(),
|
||||||
|
'\u{F189}' => "vk".to_owned(),
|
||||||
|
'\u{F1A6}' => "digg".to_owned(),
|
||||||
|
'\u{F1CA}' => "web-vine".to_owned(),
|
||||||
|
'\u{F8FF}' => "os-apple".to_owned(),
|
||||||
|
|
||||||
|
// Special private-use-area extensions found in `Ubuntu-Light.ttf`
|
||||||
|
'\u{F000}' => "uniF000".to_owned(),
|
||||||
|
'\u{F001}' => "fi".to_owned(),
|
||||||
|
'\u{F002}' => "fl".to_owned(),
|
||||||
|
'\u{F506}' => "one seventh".to_owned(),
|
||||||
|
'\u{F507}' => "two sevenths".to_owned(),
|
||||||
|
'\u{F508}' => "three sevenths".to_owned(),
|
||||||
|
'\u{F509}' => "four sevenths".to_owned(),
|
||||||
|
'\u{F50A}' => "fiv esevenths".to_owned(),
|
||||||
|
'\u{F50B}' => "six sevenths".to_owned(),
|
||||||
|
'\u{F50C}' => "one ninth".to_owned(),
|
||||||
|
'\u{F50D}' => "two ninths".to_owned(),
|
||||||
|
'\u{F50E}' => "four ninths".to_owned(),
|
||||||
|
'\u{F50F}' => "five ninths".to_owned(),
|
||||||
|
'\u{F510}' => "seven ninths".to_owned(),
|
||||||
|
'\u{F511}' => "eight ninths".to_owned(),
|
||||||
|
'\u{F800}' => "zero.alt".to_owned(),
|
||||||
|
'\u{F801}' => "one.alt".to_owned(),
|
||||||
|
'\u{F802}' => "two.alt".to_owned(),
|
||||||
|
'\u{F803}' => "three.alt".to_owned(),
|
||||||
|
'\u{F804}' => "four.alt".to_owned(),
|
||||||
|
'\u{F805}' => "five.alt".to_owned(),
|
||||||
|
'\u{F806}' => "six.alt".to_owned(),
|
||||||
|
'\u{F807}' => "seven.alt".to_owned(),
|
||||||
|
'\u{F808}' => "eight.alt".to_owned(),
|
||||||
|
'\u{F809}' => "nine.alt".to_owned(),
|
||||||
|
'\u{F80A}' => "zero.sups".to_owned(),
|
||||||
|
'\u{F80B}' => "one.sups".to_owned(),
|
||||||
|
'\u{F80C}' => "two.sups".to_owned(),
|
||||||
|
'\u{F80D}' => "three.sups".to_owned(),
|
||||||
|
'\u{F80E}' => "four.sups".to_owned(),
|
||||||
|
'\u{F80F}' => "five.sups".to_owned(),
|
||||||
|
'\u{F810}' => "six.sups".to_owned(),
|
||||||
|
'\u{F811}' => "seven.sups".to_owned(),
|
||||||
|
'\u{F812}' => "eight.sups".to_owned(),
|
||||||
|
'\u{F813}' => "nine.sups".to_owned(),
|
||||||
|
'\u{F814}' => "zero.sinf".to_owned(),
|
||||||
|
'\u{F815}' => "one.sinf".to_owned(),
|
||||||
|
'\u{F816}' => "two.sinf".to_owned(),
|
||||||
|
'\u{F817}' => "three.sinf".to_owned(),
|
||||||
|
'\u{F818}' => "four.sinf".to_owned(),
|
||||||
|
'\u{F819}' => "five.sinf".to_owned(),
|
||||||
|
'\u{F81A}' => "six.sinf".to_owned(),
|
||||||
|
'\u{F81B}' => "seven.sinf".to_owned(),
|
||||||
|
'\u{F81C}' => "eight.sinf".to_owned(),
|
||||||
|
'\u{F81D}' => "nine.sinf".to_owned(),
|
||||||
|
|
||||||
|
_ => "unknown".to_owned(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -9,8 +9,6 @@ pub mod dancing_strings;
|
||||||
pub mod demo_app_windows;
|
pub mod demo_app_windows;
|
||||||
pub mod drag_and_drop;
|
pub mod drag_and_drop;
|
||||||
pub mod font_book;
|
pub mod font_book;
|
||||||
pub mod font_contents_emoji;
|
|
||||||
pub mod font_contents_ubuntu;
|
|
||||||
pub mod layout_test;
|
pub mod layout_test;
|
||||||
pub mod misc_demo_window;
|
pub mod misc_demo_window;
|
||||||
pub mod multi_touch;
|
pub mod multi_touch;
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use ahash::AHashMap;
|
use ahash::AHashMap;
|
||||||
use emath::{vec2, Vec2};
|
use emath::{vec2, Vec2};
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -101,6 +102,24 @@ impl FontImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An un-ordered iterator over all supported characters.
|
||||||
|
fn characters(&self) -> impl Iterator<Item = char> + '_ {
|
||||||
|
use ab_glyph::Font as _;
|
||||||
|
self.ab_glyph_font
|
||||||
|
.codepoint_ids()
|
||||||
|
.map(|(_, chr)| chr)
|
||||||
|
.filter(|chr| {
|
||||||
|
!matches!(
|
||||||
|
chr,
|
||||||
|
// Strip out a religious symbol with secondary nefarious interpretation:
|
||||||
|
'\u{534d}' | '\u{5350}' |
|
||||||
|
|
||||||
|
// Ignore ubuntu-specific stuff in `Ubuntu-Light.ttf`:
|
||||||
|
'\u{E0FF}' | '\u{EFFD}' | '\u{F0FF}' | '\u{F200}'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// `\n` will result in `None`
|
/// `\n` will result in `None`
|
||||||
fn glyph_info(&self, c: char) -> Option<GlyphInfo> {
|
fn glyph_info(&self, c: char) -> Option<GlyphInfo> {
|
||||||
{
|
{
|
||||||
|
@ -173,6 +192,7 @@ type FontIndex = usize;
|
||||||
pub struct Font {
|
pub struct Font {
|
||||||
text_style: TextStyle,
|
text_style: TextStyle,
|
||||||
fonts: Vec<Arc<FontImpl>>,
|
fonts: Vec<Arc<FontImpl>>,
|
||||||
|
characters: std::collections::BTreeSet<char>,
|
||||||
replacement_glyph: (FontIndex, GlyphInfo),
|
replacement_glyph: (FontIndex, GlyphInfo),
|
||||||
pixels_per_point: f32,
|
pixels_per_point: f32,
|
||||||
row_height: f32,
|
row_height: f32,
|
||||||
|
@ -181,10 +201,16 @@ pub struct Font {
|
||||||
|
|
||||||
impl Font {
|
impl Font {
|
||||||
pub fn new(text_style: TextStyle, fonts: Vec<Arc<FontImpl>>) -> Self {
|
pub fn new(text_style: TextStyle, fonts: Vec<Arc<FontImpl>>) -> Self {
|
||||||
|
let mut characters = BTreeSet::new();
|
||||||
|
for font in &fonts {
|
||||||
|
characters.extend(font.characters());
|
||||||
|
}
|
||||||
|
|
||||||
if fonts.is_empty() {
|
if fonts.is_empty() {
|
||||||
return Self {
|
return Self {
|
||||||
text_style,
|
text_style,
|
||||||
fonts,
|
fonts,
|
||||||
|
characters,
|
||||||
replacement_glyph: Default::default(),
|
replacement_glyph: Default::default(),
|
||||||
pixels_per_point: 0.0,
|
pixels_per_point: 0.0,
|
||||||
row_height: 0.0,
|
row_height: 0.0,
|
||||||
|
@ -198,6 +224,7 @@ impl Font {
|
||||||
let mut slf = Self {
|
let mut slf = Self {
|
||||||
text_style,
|
text_style,
|
||||||
fonts,
|
fonts,
|
||||||
|
characters,
|
||||||
replacement_glyph: Default::default(),
|
replacement_glyph: Default::default(),
|
||||||
pixels_per_point,
|
pixels_per_point,
|
||||||
row_height,
|
row_height,
|
||||||
|
@ -230,6 +257,11 @@ impl Font {
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All supported characters
|
||||||
|
pub fn characters(&self) -> &BTreeSet<char> {
|
||||||
|
&self.characters
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn text_style(&self) -> TextStyle {
|
pub fn text_style(&self) -> TextStyle {
|
||||||
self.text_style
|
self.text_style
|
||||||
|
|
Loading…
Reference in a new issue