mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00
Clean up FontRequest interface
Represent a non-specified pixel size and font weight through a None option. This is cleaner and has the added benefit that the backend can now easily decide what the default size/weight should be.
This commit is contained in:
parent
36c41ef758
commit
35f51fe339
4 changed files with 81 additions and 78 deletions
|
@ -268,14 +268,16 @@ impl<T> CachedGraphicsData<T> {
|
|||
pub type RenderingCache<T> = vec_arena::Arena<CachedGraphicsData<T>>;
|
||||
|
||||
/// FontRequest collects all the developer-configurable properties for fonts, such as family, weight, etc.
|
||||
/// It is submitted as a request to the platform font system (i.e. CoreText on macOS) and in exchange we
|
||||
/// store a Rc<FontHandle>
|
||||
/// It is submitted as a request to the platform font system (i.e. CoreText on macOS) and in exchange the
|
||||
/// backend returns a Box<dyn Font>.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct FontRequest {
|
||||
pub family: SharedString,
|
||||
pub weight: i32,
|
||||
pub pixel_size: f32,
|
||||
/// If the weight is None, the the system default font weight should be used.
|
||||
pub weight: Option<i32>,
|
||||
/// If the pixel size is None, the system default font size should be used.
|
||||
pub pixel_size: Option<f32>,
|
||||
}
|
||||
|
||||
pub trait Font {
|
||||
|
|
|
@ -66,9 +66,6 @@ impl Default for TextVerticalAlignment {
|
|||
}
|
||||
}
|
||||
|
||||
const DEFAULT_FONT_SIZE: f32 = 12.;
|
||||
const DEFAULT_FONT_WEIGHT: i32 = 400;
|
||||
|
||||
/// The implementation of the `Text` element
|
||||
#[repr(C)]
|
||||
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
||||
|
@ -99,7 +96,7 @@ impl Item for Text {
|
|||
fn layouting_info(self: Pin<&Self>, window: &ComponentWindow) -> LayoutInfo {
|
||||
let text = self.text();
|
||||
|
||||
if let Some(font) = self.font(window) {
|
||||
if let Some(font) = window.0.font(self.font_request()) {
|
||||
let width = font.text_width(&text);
|
||||
let height = font.height();
|
||||
LayoutInfo { min_width: width, min_height: height, ..LayoutInfo::default() }
|
||||
|
@ -134,36 +131,27 @@ impl ItemConsts for Text {
|
|||
}
|
||||
|
||||
impl Text {
|
||||
pub fn font_pixel_size(self: Pin<&Self>, scale_factor: f32) -> f32 {
|
||||
let font_size = self.font_size();
|
||||
if font_size == 0.0 {
|
||||
DEFAULT_FONT_SIZE * scale_factor
|
||||
} else {
|
||||
font_size
|
||||
}
|
||||
}
|
||||
|
||||
pub fn font_request(self: Pin<&Self>, scale_factor: f32) -> crate::graphics::FontRequest {
|
||||
pub fn font_request(self: Pin<&Self>) -> crate::graphics::FontRequest {
|
||||
crate::graphics::FontRequest {
|
||||
family: self.font_family(),
|
||||
weight: {
|
||||
let weight = self.font_weight();
|
||||
if weight == 0 {
|
||||
DEFAULT_FONT_WEIGHT
|
||||
None
|
||||
} else {
|
||||
weight
|
||||
Some(weight)
|
||||
}
|
||||
},
|
||||
pixel_size: {
|
||||
let font_size = self.font_size();
|
||||
if font_size == 0.0 {
|
||||
None
|
||||
} else {
|
||||
Some(font_size)
|
||||
}
|
||||
},
|
||||
pixel_size: self.font_pixel_size(scale_factor),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn font(
|
||||
self: Pin<&Self>,
|
||||
window: &ComponentWindow,
|
||||
) -> Option<Box<dyn crate::graphics::Font>> {
|
||||
window.0.font(self.font_request(window.scale_factor()))
|
||||
}
|
||||
}
|
||||
|
||||
/// The implementation of the `TextInput` element
|
||||
|
@ -205,7 +193,7 @@ impl Item for TextInput {
|
|||
}
|
||||
|
||||
fn layouting_info(self: Pin<&Self>, window: &ComponentWindow) -> LayoutInfo {
|
||||
if let Some(font) = self.font(window) {
|
||||
if let Some(font) = window.0.font(self.font_request()) {
|
||||
let width = font.text_width("********************");
|
||||
let height = font.height();
|
||||
|
||||
|
@ -231,7 +219,7 @@ impl Item for TextInput {
|
|||
}
|
||||
|
||||
let text = self.text();
|
||||
let font = match self.font(window) {
|
||||
let font = match window.0.font(self.font_request()) {
|
||||
Some(font) => font,
|
||||
None => return InputEventResult::EventIgnored,
|
||||
};
|
||||
|
@ -545,36 +533,27 @@ impl TextInput {
|
|||
}
|
||||
}
|
||||
|
||||
fn font_pixel_size(self: Pin<&Self>, scale_factor: f32) -> f32 {
|
||||
let font_size = self.font_size();
|
||||
if font_size == 0.0 {
|
||||
DEFAULT_FONT_SIZE * scale_factor
|
||||
} else {
|
||||
font_size
|
||||
}
|
||||
}
|
||||
|
||||
pub fn font_request(self: Pin<&Self>, scale_factor: f32) -> crate::graphics::FontRequest {
|
||||
pub fn font_request(self: Pin<&Self>) -> crate::graphics::FontRequest {
|
||||
crate::graphics::FontRequest {
|
||||
family: self.font_family(),
|
||||
weight: {
|
||||
let weight = self.font_weight();
|
||||
if weight == 0 {
|
||||
DEFAULT_FONT_WEIGHT
|
||||
None
|
||||
} else {
|
||||
weight
|
||||
Some(weight)
|
||||
}
|
||||
},
|
||||
pixel_size: {
|
||||
let font_size = self.font_size();
|
||||
if font_size == 0.0 {
|
||||
None
|
||||
} else {
|
||||
Some(font_size)
|
||||
}
|
||||
},
|
||||
pixel_size: self.font_pixel_size(scale_factor),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn font(
|
||||
self: Pin<&Self>,
|
||||
window: &ComponentWindow,
|
||||
) -> Option<Box<dyn crate::graphics::Font>> {
|
||||
window.0.font(self.font_request(window.scale_factor()))
|
||||
}
|
||||
}
|
||||
|
||||
thread_local!(pub(crate) static CLIPBOARD : std::cell::RefCell<copypasta::ClipboardContext> = std::cell::RefCell::new(copypasta::ClipboardContext::new().unwrap()));
|
||||
|
|
|
@ -89,6 +89,11 @@ pub trait GenericWindow {
|
|||
/// Close the active popup if any
|
||||
fn close_popup(&self);
|
||||
|
||||
/// Return a font trait object for the given font request. This is typically provided by the backend and
|
||||
/// requested by text related items in order to measure text metrics with the item's chosen font.
|
||||
/// Note that if the FontRequest's pixel_size is 0, it is interpreted as the undefined size and that the
|
||||
/// system default font size should be used for the returned font.
|
||||
/// With some backends this may return none unless the window is mapped.
|
||||
fn font(&self, request: crate::graphics::FontRequest)
|
||||
-> Option<Box<dyn crate::graphics::Font>>;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ pub(crate) mod eventloop;
|
|||
type CanvasRc = Rc<RefCell<femtovg::Canvas<femtovg::renderer::OpenGl>>>;
|
||||
type ItemRenderingCacheRc = Rc<RefCell<RenderingCache<Option<GPUCachedData>>>>;
|
||||
|
||||
pub const DEFAULT_FONT_SIZE: f32 = 12.;
|
||||
pub const DEFAULT_FONT_WEIGHT: i32 = 400; // CSS normal
|
||||
|
||||
struct CachedImage {
|
||||
id: femtovg::ImageId,
|
||||
canvas: CanvasRc,
|
||||
|
@ -95,7 +98,7 @@ fn try_load_app_font(canvas: &CanvasRc, request: &FontRequest) -> Option<femtovg
|
|||
};
|
||||
let query = fontdb::Query {
|
||||
families: &[family],
|
||||
weight: fontdb::Weight(request.weight as u16),
|
||||
weight: fontdb::Weight(request.weight.unwrap() as u16),
|
||||
..Default::default()
|
||||
};
|
||||
APPLICATION_FONTS.with(|font_db| {
|
||||
|
@ -121,7 +124,7 @@ fn load_system_font(canvas: &CanvasRc, request: &FontRequest) -> femtovg::FontId
|
|||
.select_best_match(
|
||||
&[family_name, font_kit::family_name::FamilyName::SansSerif],
|
||||
&font_kit::properties::Properties::new()
|
||||
.weight(font_kit::properties::Weight(request.weight as f32)),
|
||||
.weight(font_kit::properties::Weight(request.weight.unwrap() as f32)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -138,14 +141,25 @@ fn load_system_font(canvas: &CanvasRc, request: &FontRequest) -> femtovg::FontId
|
|||
}
|
||||
|
||||
impl FontDatabase {
|
||||
fn font(&mut self, canvas: &CanvasRc, request: FontRequest) -> femtovg::FontId {
|
||||
self.0
|
||||
.entry(FontCacheKey::new(&request))
|
||||
.or_insert_with(|| {
|
||||
try_load_app_font(canvas, &request)
|
||||
.unwrap_or_else(|| load_system_font(canvas, &request))
|
||||
})
|
||||
.clone()
|
||||
fn font(&mut self, canvas: &CanvasRc, mut request: FontRequest, scale_factor: f32) -> GLFont {
|
||||
request.pixel_size = request.pixel_size.or(Some(DEFAULT_FONT_SIZE * scale_factor));
|
||||
request.weight = request.weight.or(Some(DEFAULT_FONT_WEIGHT));
|
||||
|
||||
GLFont {
|
||||
font_id: self
|
||||
.0
|
||||
.entry(FontCacheKey {
|
||||
family: request.family.clone(),
|
||||
weight: request.weight.unwrap(),
|
||||
})
|
||||
.or_insert_with(|| {
|
||||
try_load_app_font(canvas, &request)
|
||||
.unwrap_or_else(|| load_system_font(canvas, &request))
|
||||
})
|
||||
.clone(),
|
||||
canvas: canvas.clone(),
|
||||
pixel_size: request.pixel_size.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -357,12 +371,11 @@ impl GraphicsBackend for GLRenderer {
|
|||
}
|
||||
|
||||
fn font(&mut self, request: FontRequest) -> Box<dyn Font> {
|
||||
let pixel_size = request.pixel_size;
|
||||
Box::new(GLFont {
|
||||
font_id: self.loaded_fonts.borrow_mut().font(&self.canvas, request),
|
||||
canvas: self.canvas.clone(),
|
||||
pixel_size,
|
||||
})
|
||||
Box::new(self.loaded_fonts.borrow_mut().font(
|
||||
&self.canvas,
|
||||
request,
|
||||
self.window().scale_factor() as f32,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,13 +596,13 @@ impl ItemRenderer for GLItemRenderer {
|
|||
fn draw_text(&mut self, pos: Point, text: std::pin::Pin<&sixtyfps_corelib::items::Text>) {
|
||||
use sixtyfps_corelib::items::{TextHorizontalAlignment, TextVerticalAlignment};
|
||||
|
||||
let font_id =
|
||||
self.loaded_fonts.borrow_mut().font(&self.canvas, text.font_request(self.scale_factor));
|
||||
let font = self.loaded_fonts.borrow_mut().font(
|
||||
&self.canvas,
|
||||
text.font_request(),
|
||||
self.scale_factor,
|
||||
);
|
||||
|
||||
let mut paint = femtovg::Paint::color(text.color().into());
|
||||
paint.set_font(&[font_id]);
|
||||
paint.set_font_size(text.font_pixel_size(self.scale_factor()));
|
||||
paint.set_text_baseline(femtovg::Baseline::Top);
|
||||
let paint = font.paint(text.color().into());
|
||||
|
||||
let text_str = text.text();
|
||||
|
||||
|
@ -705,12 +718,6 @@ struct FontCacheKey {
|
|||
weight: i32,
|
||||
}
|
||||
|
||||
impl FontCacheKey {
|
||||
fn new(request: &FontRequest) -> Self {
|
||||
Self { family: request.family.clone(), weight: request.weight }
|
||||
}
|
||||
}
|
||||
|
||||
struct GLFont {
|
||||
font_id: femtovg::FontId,
|
||||
pixel_size: f32,
|
||||
|
@ -738,6 +745,16 @@ impl Font for GLFont {
|
|||
}
|
||||
}
|
||||
|
||||
impl GLFont {
|
||||
fn paint(&self, color: Color) -> femtovg::Paint {
|
||||
let mut paint = femtovg::Paint::color(color.into());
|
||||
paint.set_font(&[self.font_id]);
|
||||
paint.set_font_size(self.pixel_size);
|
||||
paint.set_text_baseline(femtovg::Baseline::Top);
|
||||
paint
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_window() -> ComponentWindow {
|
||||
ComponentWindow::new(GraphicsWindow::new(|event_loop, window_builder| {
|
||||
GLRenderer::new(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue