Skip to content

Commit

Permalink
Merge pull request #445 from kas-gui/work1
Browse files Browse the repository at this point in the history
kas-text revisions: text_is_rtl, configure, wrap_width, remove Environment, fonts::library
  • Loading branch information
dhardy committed Mar 10, 2024
2 parents 49ce75b + a137663 commit b808a8e
Show file tree
Hide file tree
Showing 25 changed files with 291 additions and 232 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,7 @@ members = [
"crates/kas-view",
"examples/mandlebrot",
]

[patch.crates-io.kas-text]
git = "https://github.com/kas-gui/kas-text.git"
rev = "d9d2a99b7d94deeea48d67f3b7ba9237a12cea6d"
18 changes: 12 additions & 6 deletions crates/kas-core/src/decorations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! Note: due to definition in kas-core, some widgets must be duplicated.

use crate::event::{CursorIcon, ResizeDirection};
use crate::text::Text;
use crate::text::{NotReady, Text};
use crate::theme::TextClass;
use kas::prelude::*;
use kas::theme::MarkStyle;
Expand Down Expand Up @@ -125,22 +125,27 @@ impl_scope! {
}

impl Layout for Self {
#[inline]
fn size_rules(&mut self, sizer: SizeCx, mut axis: AxisInfo) -> SizeRules {
axis.set_default_align_hv(Align::Center, Align::Center);
sizer.text_rules(&mut self.label, Self::CLASS, axis)
sizer.text_rules(&mut self.label, axis)
}

fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
self.core.rect = rect;
cx.text_set_size(&mut self.label, Self::CLASS, rect.size, None);
cx.text_set_size(&mut self.label, rect.size);
}

fn draw(&mut self, mut draw: DrawCx) {
draw.text(self.rect(), &self.label, Self::CLASS);
}
}

impl Events for Self {
fn configure(&mut self, cx: &mut ConfigCx) {
cx.text_configure(&mut self.label, Self::CLASS);
}
}

impl HasStr for Self {
fn get_str(&self) -> &str {
self.label.as_str()
Expand All @@ -150,9 +155,10 @@ impl_scope! {
impl HasString for Self {
fn set_string(&mut self, string: String) -> Action {
self.label.set_string(string);
match self.label.try_prepare() {
match self.label.prepare() {
Err(NotReady) => Action::empty(),
Ok(false) => Action::REDRAW,
Ok(true) => Action::RESIZE,
_ => Action::REDRAW,
}
}
}
Expand Down
29 changes: 17 additions & 12 deletions crates/kas-core/src/event/cx/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::messages::Erased;
use crate::text::TextApi;
use crate::theme::{Feature, SizeCx, TextClass, ThemeSize};
use crate::{Id, Node};
use cast::Cast;
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};

Expand Down Expand Up @@ -122,22 +123,26 @@ impl<'a> ConfigCx<'a> {
self.sh.align_feature(feature, rect, align)
}

/// Configure a text object
///
/// This selects a font given the [`TextClass`],
/// [theme configuration][crate::theme::Config] and
/// the loaded [fonts][crate::text::fonts].
#[inline]
pub fn text_configure(&self, text: &mut dyn TextApi, class: TextClass) {
self.sh.text_configure(text, class);
}

/// Prepare a text object
///
/// This sets the text's font, font size, wrapping and optionally alignment,
/// then performs the text preparation necessary before display.
/// Wrap and align text for display at the given `size`.
///
/// Note: setting alignment here is not necessary when the default alignment
/// is desired or when [`SizeCx::text_rules`] is used.
/// Call [`text_configure`][Self::text_configure] before this method.
#[inline]
pub fn text_set_size(
&self,
text: &mut dyn TextApi,
class: TextClass,
size: Size,
align: Option<AlignPair>,
) {
self.sh.text_set_size(text, class, size, align)
pub fn text_set_size(&self, text: &mut dyn TextApi, size: Size) {
text.set_wrap_width(size.0.cast());
text.set_bounds(size.cast());
text.prepare().expect("not configured");
}
}

Expand Down
12 changes: 9 additions & 3 deletions crates/kas-core/src/hidden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::geom::{Coord, Offset, Rect};
use crate::layout::{Align, AxisInfo, SizeRules};
use crate::text::{Text, TextApi};
use crate::theme::{DrawCx, SizeCx, TextClass};
use crate::{Id, Layout, NavAdvance, Node, Widget};
use crate::{Events, Id, Layout, NavAdvance, Node, Widget};
use kas_macros::{autoimpl, impl_scope};

impl_scope! {
Expand Down Expand Up @@ -51,19 +51,25 @@ impl_scope! {
#[inline]
fn size_rules(&mut self, sizer: SizeCx, mut axis: AxisInfo) -> SizeRules {
axis.set_default_align_hv(Align::Default, Align::Center);
sizer.text_rules(&mut self.label, Self::CLASS, axis)
sizer.text_rules(&mut self.label, axis)
}

fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
self.core.rect = rect;
cx.text_set_size(&mut self.label, Self::CLASS, rect.size, None);
cx.text_set_size(&mut self.label, rect.size);
}

fn draw(&mut self, mut draw: DrawCx) {
draw.text(self.rect(), &self.label, Self::CLASS);
}
}

impl Events for Self {
fn configure(&mut self, cx: &mut ConfigCx) {
cx.text_configure(&mut self.label, Self::CLASS);
}
}

impl HasStr for Self {
fn get_str(&self) -> &str {
self.label.as_str()
Expand Down
10 changes: 0 additions & 10 deletions crates/kas-core/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,6 @@ impl AxisInfo {
}
}

/// Size of other axis, if fixed and `vertical` matches this axis.
#[inline]
pub fn size_other_if_fixed(&self, vertical: bool) -> Option<i32> {
if vertical == self.vertical && self.has_fixed {
Some(self.other_axis)
} else {
None
}
}

/// Subtract `x` from size of other axis (if applicable)
#[inline]
pub fn sub_other(&mut self, x: i32) {
Expand Down
9 changes: 5 additions & 4 deletions crates/kas-core/src/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
//! Most of this module is simply a re-export of the [KAS Text] API, hence the
//! lower level of integration than other parts of the library.
//!
//! [`Text`] objects *must* be prepared before usage, otherwise they may appear
//! empty. Call [`ConfigCx::text_set_size`] from [`Layout::set_rect`] to set
//! text position and prepare. If text is adjusted, one may use e.g.
//! [`TextApi::prepare`] to update.
//! [`Text`] objects *must* be configured and prepared before usage, otherwise
//! they may appear empty. Call [`ConfigCx::text_config`] from
//! [`Events::configure`] and [`ConfigCx::text_set_size`] from
//! [`Layout::set_rect`] to set text position and prepare.
//! If text is adjusted, one may use e.g. [`TextApi::prepare`] to update.
//!
//! [KAS Text]: https://github.com/kas-gui/kas-text/

Expand Down
4 changes: 2 additions & 2 deletions crates/kas-core/src/theme/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//! Theme configuration

use super::{ColorsSrgb, TextClass, ThemeConfig};
use crate::text::fonts::{fonts, AddMode, FontSelector};
use crate::text::fonts::{self, AddMode, FontSelector};
use crate::Action;
use std::collections::BTreeMap;
use std::time::Duration;
Expand Down Expand Up @@ -244,7 +244,7 @@ impl ThemeConfig for Config {
/// Apply config effects which only happen on startup
fn apply_startup(&self) {
if !self.font_aliases.is_empty() {
fonts().update_db(|db| {
fonts::library().update_db(|db| {
for (family, aliases) in self.font_aliases.iter() {
db.add_aliases(
family.to_string().into(),
Expand Down
72 changes: 28 additions & 44 deletions crates/kas-core/src/theme/dimensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::cast::traits::*;
use crate::dir::Directional;
use crate::geom::{Rect, Size, Vec2};
use crate::layout::{AlignPair, AxisInfo, FrameRules, Margins, SizeRules, Stretch};
use crate::text::{fonts::FontId, TextApi, TextApiExt};
use crate::text::{fonts::FontId, Direction, TextApi};

crate::impl_scope! {
/// Parameterisation of [`Dimensions`]
Expand Down Expand Up @@ -319,50 +319,50 @@ impl<D: 'static> ThemeSize for Window<D> {

fn line_height(&self, class: TextClass) -> i32 {
let font_id = self.fonts.get(&class).cloned().unwrap_or_default();
crate::text::fonts::fonts()
crate::text::fonts::library()
.get_first_face(font_id)
.expect("invalid font_id")
.height(self.dims.dpem)
.cast_ceil()
}

fn text_rules(&self, text: &mut dyn TextApi, class: TextClass, axis: AxisInfo) -> SizeRules {
fn text_configure(&self, text: &mut dyn TextApi, class: TextClass) {
let direction = Direction::Auto;
let font_id = self.fonts.get(&class).cloned().unwrap_or_default();
let dpem = self.dims.dpem;
let wrap = match class.multi_line() {
false => f32::INFINITY,
true => 0.0, // NOTE: finite value used as a flag
};
text.set_font_properties(direction, font_id, dpem, wrap);
text.configure().expect("invalid font_id");
}

fn text_rules(&self, text: &mut dyn TextApi, axis: AxisInfo) -> SizeRules {
let margin = match axis.is_horizontal() {
true => self.dims.m_text.0,
false => self.dims.m_text.1,
};
let margins = (margin, margin);

let mut env = text.env();

// TODO(opt): maybe font look-up should only happen during configure?
if let Some(font_id) = self.fonts.get(&class).cloned() {
env.font_id = font_id;
}
env.dpem = self.dims.dpem;
// TODO(opt): setting horizontal alignment now could avoid re-wrapping
// text. Unfortunately we don't know the desired alignment here.
let wrap = class.multi_line();
env.wrap = wrap;
let mut align_pair = text.get_align();
let align = axis.align_or_default();
if axis.is_horizontal() {
env.align.0 = align;
align_pair.0 = align;
} else {
env.align.1 = align;
}
if let Some(size) = axis.size_other_if_fixed(true) {
env.bounds.0 = size.cast();
align_pair.1 = align;
}
text.set_align(align_pair);

text.set_env(env);
let wrap = text.get_wrap_width();

if axis.is_horizontal() {
if wrap {
if wrap.is_finite() {
let min = self.dims.min_line_length;
let limit = 2 * min;
let bound: i32 = text
.measure_width(limit.cast())
.expect("invalid font_id")
.expect("not configured")
.cast_ceil();

// NOTE: using different variable-width stretch policies here can
Expand All @@ -372,36 +372,20 @@ impl<D: 'static> ThemeSize for Window<D> {
} else {
let bound: i32 = text
.measure_width(f32::INFINITY)
.expect("invalid font_id")
.expect("not configured")
.cast_ceil();
SizeRules::new(bound, bound, margins, Stretch::Filler)
}
} else {
let bound: i32 = text.measure_height().expect("invalid font_id").cast_ceil();
if wrap.is_finite() {
text.set_wrap_width(axis.other().map(|w| w.cast()).unwrap_or(f32::INFINITY));
}

let bound: i32 = text.measure_height().expect("not configured").cast_ceil();

let line_height = self.dims.dpem.cast_ceil();
let min = bound.max(line_height);
SizeRules::new(min, min, margins, Stretch::Filler)
}
}

fn text_set_size(
&self,
text: &mut dyn TextApi,
class: TextClass,
size: Size,
align: Option<AlignPair>,
) {
let mut env = text.env();
if let Some(font_id) = self.fonts.get(&class).cloned() {
env.font_id = font_id;
}
env.dpem = self.dims.dpem;
env.wrap = class.multi_line();
if let Some(align) = align {
env.align = align.into();
}
env.bounds = size.cast();
text.update_env(env).expect("invalid font_id");
}
}
Loading

0 comments on commit b808a8e

Please sign in to comment.