2022-10-25 14:42:26 -06:00
|
|
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
use std::ops::Range;
|
|
|
|
|
|
2022-10-25 14:14:23 -06:00
|
|
|
pub use fontdb::{Family, Stretch, Style, Weight};
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Text color
|
2022-10-26 14:16:48 -06:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
|
|
|
|
pub struct Color(pub u32);
|
|
|
|
|
|
|
|
|
|
impl Color {
|
2022-10-27 09:07:47 -06:00
|
|
|
/// Create new color with red, green, and blue components
|
|
|
|
|
#[inline]
|
2022-10-26 14:16:48 -06:00
|
|
|
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
|
|
|
|
|
Self::rgba(r, g, b, 0xFF)
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:07:47 -06:00
|
|
|
/// Create new color with red, green, blue, and alpha components
|
|
|
|
|
#[inline]
|
2022-10-26 14:16:48 -06:00
|
|
|
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
|
|
|
|
|
Self(
|
|
|
|
|
((a as u32) << 24) |
|
|
|
|
|
((r as u32) << 16) |
|
|
|
|
|
((g as u32) << 8) |
|
|
|
|
|
(b as u32)
|
|
|
|
|
)
|
|
|
|
|
}
|
2022-10-27 09:07:47 -06:00
|
|
|
|
|
|
|
|
/// Get the red component
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn r(&self) -> u8 {
|
|
|
|
|
((self.0 & 0x00FF0000) >> 16) as u8
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get the green component
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn g(&self) -> u8 {
|
|
|
|
|
((self.0 & 0x0000FF00) >> 8) as u8
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get the blue component
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn b(&self) -> u8 {
|
|
|
|
|
(self.0 & 0x000000FF) as u8
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get the alpha component
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn a(&self) -> u8 {
|
|
|
|
|
((self.0 & 0xFF000000) >> 24) as u8
|
|
|
|
|
}
|
2022-10-26 14:16:48 -06:00
|
|
|
}
|
|
|
|
|
|
2022-11-04 09:44:54 -06:00
|
|
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
|
|
|
|
pub enum FamilyOwned {
|
|
|
|
|
Name(String),
|
|
|
|
|
Serif,
|
|
|
|
|
SansSerif,
|
|
|
|
|
Cursive,
|
|
|
|
|
Fantasy,
|
|
|
|
|
Monospace,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FamilyOwned {
|
|
|
|
|
pub fn new(family: Family) -> Self {
|
|
|
|
|
match family {
|
|
|
|
|
Family::Name(name) => FamilyOwned::Name(name.to_string()),
|
|
|
|
|
Family::Serif => FamilyOwned::Serif,
|
|
|
|
|
Family::SansSerif => FamilyOwned::SansSerif,
|
|
|
|
|
Family::Cursive => FamilyOwned::Cursive,
|
|
|
|
|
Family::Fantasy => FamilyOwned::Fantasy,
|
|
|
|
|
Family::Monospace => FamilyOwned::Monospace,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn as_family(&self) -> Family {
|
|
|
|
|
match self {
|
|
|
|
|
FamilyOwned::Name(name) => Family::Name(&name),
|
|
|
|
|
FamilyOwned::Serif => Family::Serif,
|
|
|
|
|
FamilyOwned::SansSerif => Family::SansSerif,
|
|
|
|
|
FamilyOwned::Cursive => Family::Cursive,
|
|
|
|
|
FamilyOwned::Fantasy => Family::Fantasy,
|
|
|
|
|
FamilyOwned::Monospace => Family::Monospace,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Text attributes
|
2022-10-26 12:23:03 -06:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
2022-10-25 14:14:23 -06:00
|
|
|
pub struct Attrs<'a> {
|
2022-10-26 14:16:48 -06:00
|
|
|
//TODO: should this be an option?
|
|
|
|
|
pub color_opt: Option<Color>,
|
2022-10-25 14:14:23 -06:00
|
|
|
pub family: Family<'a>,
|
|
|
|
|
pub monospaced: bool,
|
|
|
|
|
pub stretch: Stretch,
|
|
|
|
|
pub style: Style,
|
|
|
|
|
pub weight: Weight,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> Attrs<'a> {
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Create a new set of attributes with sane defaults
|
|
|
|
|
///
|
|
|
|
|
/// This defaults to a regular Sans-Serif font.
|
2022-10-25 14:14:23 -06:00
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self {
|
2022-10-26 14:16:48 -06:00
|
|
|
color_opt: None,
|
2022-10-25 14:14:23 -06:00
|
|
|
family: Family::SansSerif,
|
|
|
|
|
monospaced: false,
|
|
|
|
|
stretch: Stretch::Normal,
|
|
|
|
|
style: Style::Normal,
|
|
|
|
|
weight: Weight::NORMAL,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Set [Color]
|
2022-10-26 14:16:48 -06:00
|
|
|
pub fn color(mut self, color: Color) -> Self {
|
|
|
|
|
self.color_opt = Some(color);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Set [Family]
|
2022-10-25 14:14:23 -06:00
|
|
|
pub fn family(mut self, family: Family<'a>) -> Self {
|
|
|
|
|
self.family = family;
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Set monospaced
|
2022-10-25 14:14:23 -06:00
|
|
|
pub fn monospaced(mut self, monospaced: bool) -> Self {
|
|
|
|
|
self.monospaced = monospaced;
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Set [Stretch]
|
2022-10-25 14:14:23 -06:00
|
|
|
pub fn stretch(mut self, stretch: Stretch) -> Self {
|
|
|
|
|
self.stretch = stretch;
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Set [Style]
|
2022-10-25 14:14:23 -06:00
|
|
|
pub fn style(mut self, style: Style) -> Self {
|
|
|
|
|
self.style = style;
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Set [Weight]
|
2022-10-25 14:14:23 -06:00
|
|
|
pub fn weight(mut self, weight: Weight) -> Self {
|
|
|
|
|
self.weight = weight;
|
|
|
|
|
self
|
|
|
|
|
}
|
2022-10-25 15:51:28 -06:00
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Check if font matches
|
2022-10-25 15:51:28 -06:00
|
|
|
pub fn matches(&self, face: &fontdb::FaceInfo) -> bool {
|
|
|
|
|
//TODO: smarter way of including emoji
|
2022-10-27 08:25:30 -06:00
|
|
|
face.post_script_name.contains("Emoji") ||
|
|
|
|
|
(
|
|
|
|
|
face.style == self.style &&
|
|
|
|
|
face.weight == self.weight &&
|
|
|
|
|
face.stretch == self.stretch &&
|
|
|
|
|
face.monospaced == self.monospaced
|
|
|
|
|
)
|
2022-10-25 15:51:28 -06:00
|
|
|
}
|
2022-10-26 15:16:06 -06:00
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Check if this set of attributes can be shaped with another
|
2022-10-26 15:16:06 -06:00
|
|
|
pub fn compatible(&self, other: &Self) -> bool {
|
|
|
|
|
self.family == other.family
|
|
|
|
|
&& self.monospaced == other.monospaced
|
|
|
|
|
&& self.stretch == other.stretch
|
|
|
|
|
&& self.style == other.style
|
|
|
|
|
&& self.weight == other.weight
|
|
|
|
|
}
|
2022-10-25 14:14:23 -06:00
|
|
|
}
|
2022-10-26 14:16:48 -06:00
|
|
|
|
2022-11-04 09:44:54 -06:00
|
|
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
|
|
|
|
pub struct AttrsOwned {
|
|
|
|
|
//TODO: should this be an option?
|
|
|
|
|
pub color_opt: Option<Color>,
|
|
|
|
|
pub family_owned: FamilyOwned,
|
|
|
|
|
pub monospaced: bool,
|
|
|
|
|
pub stretch: Stretch,
|
|
|
|
|
pub style: Style,
|
|
|
|
|
pub weight: Weight,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl AttrsOwned {
|
|
|
|
|
pub fn new(attrs: Attrs) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
color_opt: attrs.color_opt,
|
|
|
|
|
family_owned: FamilyOwned::new(attrs.family),
|
|
|
|
|
monospaced: attrs.monospaced,
|
|
|
|
|
stretch: attrs.stretch,
|
|
|
|
|
style: attrs.style,
|
|
|
|
|
weight: attrs.weight,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn as_attrs(&self) -> Attrs {
|
|
|
|
|
Attrs {
|
|
|
|
|
color_opt: self.color_opt,
|
|
|
|
|
family: self.family_owned.as_family(),
|
|
|
|
|
monospaced: self.monospaced,
|
|
|
|
|
stretch: self.stretch,
|
|
|
|
|
style: self.style,
|
|
|
|
|
weight: self.weight,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// List of text attributes to apply to a line
|
2022-10-27 13:50:14 -06:00
|
|
|
//TODO: have this clean up the spans when changes are made
|
2022-10-26 21:27:29 -06:00
|
|
|
#[derive(Eq, PartialEq)]
|
2022-11-04 09:44:54 -06:00
|
|
|
pub struct AttrsList {
|
|
|
|
|
defaults: AttrsOwned,
|
|
|
|
|
spans: Vec<(Range<usize>, AttrsOwned)>,
|
2022-10-26 15:16:06 -06:00
|
|
|
}
|
|
|
|
|
|
2022-11-04 09:44:54 -06:00
|
|
|
impl AttrsList {
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Create a new attributes list with a set of default [Attrs]
|
2022-11-04 09:44:54 -06:00
|
|
|
pub fn new(defaults: Attrs) -> Self {
|
2022-10-26 15:16:06 -06:00
|
|
|
Self {
|
2022-11-04 09:44:54 -06:00
|
|
|
defaults: AttrsOwned::new(defaults),
|
2022-10-26 15:16:06 -06:00
|
|
|
spans: Vec::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Get the default [Attrs]
|
2022-11-04 09:44:54 -06:00
|
|
|
pub fn defaults(&self) -> Attrs {
|
|
|
|
|
self.defaults.as_attrs()
|
2022-10-26 15:16:06 -06:00
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Get the current attribute spans
|
2022-11-04 09:44:54 -06:00
|
|
|
pub fn spans(&self) -> &Vec<(Range<usize>, AttrsOwned)> {
|
2022-10-26 15:16:06 -06:00
|
|
|
&self.spans
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Clear the current attribute spans
|
2022-10-26 15:16:06 -06:00
|
|
|
pub fn clear_spans(&mut self) {
|
|
|
|
|
self.spans.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 14:51:46 -06:00
|
|
|
/// Add an attribute span, removes any previous matching parts of spans
|
2022-11-04 09:44:54 -06:00
|
|
|
pub fn add_span(&mut self, range: Range<usize>, attrs: Attrs) {
|
2022-10-29 19:56:14 -04:00
|
|
|
//do not support 1..1 even if by accident.
|
|
|
|
|
if range.start == range.end {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-10-27 14:51:46 -06:00
|
|
|
|
2022-10-29 19:56:14 -04:00
|
|
|
let mut rework_spans = Vec::with_capacity(3);
|
2022-10-27 14:51:46 -06:00
|
|
|
let mut i = 0;
|
2022-10-29 19:56:14 -04:00
|
|
|
|
|
|
|
|
//Grab intersecting parts that are not fully intersected. remove those that are.
|
|
|
|
|
//This clips or splits the parts that are outside of the range.
|
|
|
|
|
while i < self.spans.len() {
|
|
|
|
|
if self.spans[i].0.end <= range.end && self.spans[i].0.start >= range.start {
|
|
|
|
|
let _ = self.spans.remove(i);
|
|
|
|
|
} else if self.spans[i].0.end > range.end && self.spans[i].0.start >= range.start && self.spans[i].0.start <= range.end {
|
|
|
|
|
let rework = self.spans.remove(i);
|
|
|
|
|
rework_spans.push((range.end..rework.0.end, rework.1))
|
|
|
|
|
} else if self.spans[i].0.end <= range.end && self.spans[i].0.end >= range.start && self.spans[i].0.start < range.start {
|
|
|
|
|
let rework = self.spans.remove(i);
|
|
|
|
|
rework_spans.push((rework.0.start..range.start, rework.1))
|
|
|
|
|
} else if self.spans[i].0.end > range.end && self.spans[i].0.start < range.start {
|
|
|
|
|
let rework = self.spans.remove(i);
|
2022-11-04 09:44:54 -06:00
|
|
|
rework_spans.push((rework.0.start..range.start, rework.1.clone()));
|
2022-10-29 19:56:14 -04:00
|
|
|
rework_spans.push((range.end..rework.0.end, rework.1));
|
|
|
|
|
} else if self.spans[i].0.start > range.end {
|
|
|
|
|
break;
|
2022-10-27 14:51:46 -06:00
|
|
|
} else {
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-29 19:56:14 -04:00
|
|
|
|
|
|
|
|
// Readd reworked arrays back.
|
|
|
|
|
for reworked in rework_spans {
|
|
|
|
|
self.spans.push(reworked);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-31 10:25:08 -06:00
|
|
|
// Combine span if possible
|
|
|
|
|
let mut combined = false;
|
|
|
|
|
for span in self.spans.iter_mut() {
|
2022-11-04 09:44:54 -06:00
|
|
|
if span.1.as_attrs() != attrs {
|
2022-10-31 10:25:08 -06:00
|
|
|
// Ignore not matching attrs
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if span.0.end == range.start {
|
|
|
|
|
// Extend span with range at end
|
|
|
|
|
span.0.end = range.end;
|
|
|
|
|
combined = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if span.0.start == range.end {
|
|
|
|
|
// Extend span with range at start
|
|
|
|
|
span.0.start = range.start;
|
|
|
|
|
combined = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ! combined {
|
|
|
|
|
//Finally lets add the new span. it should fit now.
|
2022-11-04 09:44:54 -06:00
|
|
|
self.spans.push((range, AttrsOwned::new(attrs)));
|
2022-10-31 10:25:08 -06:00
|
|
|
}
|
2022-10-29 19:56:14 -04:00
|
|
|
|
|
|
|
|
//sort by start to speed up further additions
|
2022-10-31 10:25:08 -06:00
|
|
|
self.spans.sort_by(|a, b| a.0.start.partial_cmp(&b.0.start).unwrap());
|
2022-10-26 15:16:06 -06:00
|
|
|
}
|
|
|
|
|
|
2022-10-27 09:56:53 -06:00
|
|
|
/// Get the highest priority attribute span for a range
|
|
|
|
|
///
|
2022-10-29 19:56:14 -04:00
|
|
|
/// This returns the first span that contains the range
|
2022-11-04 09:44:54 -06:00
|
|
|
pub fn get_span(&self, range: Range<usize>) -> Attrs {
|
2022-10-29 19:56:14 -04:00
|
|
|
for span in self.spans.iter() {
|
2022-10-27 09:56:53 -06:00
|
|
|
if range.start >= span.0.start && range.end <= span.0.end {
|
2022-11-04 09:44:54 -06:00
|
|
|
return span.1.as_attrs();
|
2022-10-26 15:16:06 -06:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-04 09:44:54 -06:00
|
|
|
self.defaults.as_attrs()
|
2022-10-26 15:16:06 -06:00
|
|
|
}
|
2022-10-27 09:56:53 -06:00
|
|
|
|
|
|
|
|
/// Split attributes list at an offset
|
|
|
|
|
pub fn split_off(&mut self, index: usize) -> Self {
|
2022-11-04 09:44:54 -06:00
|
|
|
let mut new = Self::new(self.defaults.as_attrs());
|
2022-10-27 09:56:53 -06:00
|
|
|
let mut i = 0;
|
|
|
|
|
while i < self.spans.len() {
|
|
|
|
|
if self.spans[i].0.end <= index {
|
|
|
|
|
// Leave this in the previous attributes list
|
|
|
|
|
i += 1;
|
|
|
|
|
} else if self.spans[i].0.start >= index {
|
|
|
|
|
// Move this to the new attributes list
|
|
|
|
|
let (range, attrs) = self.spans.remove(i);
|
|
|
|
|
new.spans.push((
|
|
|
|
|
range.start - index..range.end - index,
|
|
|
|
|
attrs
|
|
|
|
|
));
|
|
|
|
|
} else {
|
|
|
|
|
// New span has index..end
|
|
|
|
|
new.spans.push((
|
|
|
|
|
0..self.spans[i].0.end - index,
|
2022-11-04 09:44:54 -06:00
|
|
|
self.spans[i].1.clone()
|
2022-10-27 09:56:53 -06:00
|
|
|
));
|
|
|
|
|
// Old span has start..index
|
|
|
|
|
self.spans[i].0.end = index;
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
new
|
|
|
|
|
}
|
2022-10-26 14:16:48 -06:00
|
|
|
}
|