mirror of
https://github.com/danbulant/mangui
synced 2026-05-19 03:58:34 +00:00
working uno-like styles generation
This commit is contained in:
parent
4f454684d3
commit
0d43e248b1
14 changed files with 1408 additions and 228 deletions
1105
Cargo.lock
generated
1105
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -6,5 +6,6 @@ members = [
|
|||
"mangades",
|
||||
"rusalka",
|
||||
"rusalka-macro",
|
||||
"mangades-plain"
|
||||
"mangades-plain",
|
||||
"uno-gen"
|
||||
]
|
||||
|
|
@ -4,7 +4,7 @@ use mangui::{MainEntry, SharedNode};
|
|||
use mangui::femtovg::Paint;
|
||||
use mangui::nodes::text::Text;
|
||||
use mangui::nodes::{Style, TaffyStyle, ToShared};
|
||||
use mangui::taffy::{AlignItems, FlexDirection, JustifyContent, LengthPercentage, Rect};
|
||||
use mangui::taffy::{AlignItems, FlexDirection, JustifyContent, LengthPercentage, LengthPercentageAuto, Point, Rect};
|
||||
use uno_gen::uno;
|
||||
use crate::anilist::load_demo_async;
|
||||
use crate::tokens::TEXT_LARGE;
|
||||
|
|
@ -57,16 +57,11 @@ async fn main() {
|
|||
..Default::default()
|
||||
})
|
||||
.to_shared();
|
||||
let i = 2;
|
||||
uno!(gap-1 flex p-5px mt-1 mb-2 ml-[i] overflow-hidden);
|
||||
let i = LengthPercentageAuto::Length(5.);
|
||||
let title = Text::new("Mangades".to_owned(), TEXT_LARGE)
|
||||
.style(Style {
|
||||
layout: TaffyStyle {
|
||||
padding: Rect { left: LengthPercentage::Length(10.), right: LengthPercentage::Length(10.), top: LengthPercentage::Length(10.), bottom: LengthPercentage::Length(10.) },
|
||||
..Default::default()
|
||||
},
|
||||
text_fill: Some(Paint::color(*tokens::WHITE)),
|
||||
..Default::default()
|
||||
..uno!(p-10)
|
||||
})
|
||||
.to_shared();
|
||||
|
||||
|
|
|
|||
23
mangades-plain/src/tokens.rs
Normal file
23
mangades-plain/src/tokens.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use lazy_static::lazy_static;
|
||||
use mangui::cosmic_text::Metrics;
|
||||
use mangui::femtovg::Color;
|
||||
|
||||
lazy_static!{
|
||||
pub static ref BACKGROUND: Color = Color::hex("282C34");
|
||||
pub static ref RED: Color = Color::hex("E06C75");
|
||||
pub static ref GREEN: Color = Color::hex("98C379");
|
||||
pub static ref YELLOW: Color = Color::hex("E5C07B");
|
||||
pub static ref BLUE: Color = Color::hex("61AFEF");
|
||||
pub static ref MAGENTA: Color = Color::hex("C678DD");
|
||||
pub static ref CYAN: Color = Color::hex("56B6C2");
|
||||
pub static ref GRAY: Color = Color::hex("ABB2BF");
|
||||
pub static ref WHITE: Color = Color::hex("FFFFFF");
|
||||
pub static ref BLACK: Color = Color::hex("000000");
|
||||
}
|
||||
|
||||
pub static TEXT_NORMAL: Metrics = Metrics::new(16., 20.);
|
||||
pub static TEXT_SMALL: Metrics = Metrics::new(14., 18.);
|
||||
pub static TEXT_TINY: Metrics = Metrics::new(12., 16.);
|
||||
pub static TEXT_LARGE: Metrics = Metrics::new(20., 24.);
|
||||
pub static TEXT_HUGE: Metrics = Metrics::new(24., 30.);
|
||||
pub static TEXT_GIANT: Metrics = Metrics::new(32., 36.);
|
||||
|
|
@ -2,20 +2,20 @@ use std::sync::Arc;
|
|||
use mangui::SharedNode;
|
||||
|
||||
pub fn detach(node: &SharedNode) {
|
||||
if let Some(parent) = node.read().unwrap().parent() {
|
||||
parent.write().unwrap().remove_child(node).unwrap();
|
||||
if let Some(parent) = node.lock().unwrap().parent() {
|
||||
parent.lock().unwrap().remove_child(node).unwrap();
|
||||
}
|
||||
node.clone().write().unwrap().set_parent(None);
|
||||
node.clone().lock().unwrap().set_parent(None);
|
||||
}
|
||||
|
||||
pub fn insert(parent: &SharedNode, node: &SharedNode, before: Option<&SharedNode>) {
|
||||
if node.read().unwrap().parent().is_some() && !Arc::ptr_eq(&node.read().unwrap().parent().unwrap(), parent) {
|
||||
if node.lock().unwrap().parent().is_some() && !Arc::ptr_eq(&node.lock().unwrap().parent().unwrap(), parent) {
|
||||
detach(node);
|
||||
}
|
||||
match before {
|
||||
Some(before) => {
|
||||
parent.write().unwrap().add_child_before(node.clone(), before).unwrap();
|
||||
node.write().unwrap().set_parent(Some(Arc::downgrade(parent)));
|
||||
parent.lock().unwrap().add_child_before(node.clone(), before).unwrap();
|
||||
node.lock().unwrap().set_parent(Some(Arc::downgrade(parent)));
|
||||
},
|
||||
None => {
|
||||
append(parent, node);
|
||||
|
|
@ -24,6 +24,6 @@ pub fn insert(parent: &SharedNode, node: &SharedNode, before: Option<&SharedNode
|
|||
}
|
||||
|
||||
pub fn append(parent: &SharedNode, node: &SharedNode) {
|
||||
parent.write().unwrap().add_child(node.clone()).unwrap();
|
||||
node.write().unwrap().set_parent(Some(Arc::downgrade(parent)));
|
||||
parent.lock().unwrap().add_child(node.clone()).unwrap();
|
||||
node.lock().unwrap().set_parent(Some(Arc::downgrade(parent)));
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
femtovg = "0.8.2"
|
||||
femtovg = { path = "../femtovg" }
|
||||
glutin = "0.31.3"
|
||||
raw-window-handle = "0.5.0"
|
||||
winit = { version = "0.29.10" }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{collections::HashMap, fmt::Debug, sync::{Arc, Mutex}};
|
|||
use super::NodeEvent;
|
||||
|
||||
/// A node event handler
|
||||
pub type EventHandler = dyn FnMut(&NodeEvent);
|
||||
pub type EventHandler = dyn FnMut(&NodeEvent) + Send;
|
||||
|
||||
pub type InnerEventHandlerDataset = Arc<Mutex<HashMap<usize, Arc<Mutex<Box<EventHandler>>>>>>;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,16 +31,17 @@ use crate::nodes::{update_taffynode_children, MeasureContext, Node, render_recur
|
|||
|
||||
pub mod nodes;
|
||||
pub mod events;
|
||||
|
||||
pub use taffy;
|
||||
pub use femtovg;
|
||||
pub use cosmic_text;
|
||||
|
||||
pub type CurrentRenderer = OpenGl;
|
||||
pub type SharedNode = Arc<RwLock<dyn Node>>;
|
||||
pub type WeakSharedNode = Weak<RwLock<dyn Node>>;
|
||||
type WeakNode = Weak<RwLock<dyn Node>>;
|
||||
pub type SharedNode = Arc<Mutex<dyn Node>>;
|
||||
pub type WeakSharedNode = Weak<Mutex<dyn Node>>;
|
||||
type WeakNode = Weak<Mutex<dyn Node>>;
|
||||
type NodePtr = Option<Vec<WeakNode>>;
|
||||
type NodeLayoutMap = PtrWeakKeyHashMap<Weak<RwLock<dyn Node>>, taffy::tree::NodeId>;
|
||||
type NodeLayoutMap = PtrWeakKeyHashMap<Weak<Mutex<dyn Node>>, taffy::tree::NodeId>;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref FONT_SYSTEM: Mutex<FontSystem> = Mutex::new(FontSystem::new());
|
||||
|
|
@ -80,7 +81,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
let mut taffy_map = NodeLayoutMap::new();
|
||||
{
|
||||
let cloned = entry.root.clone();
|
||||
let root = cloned.read().unwrap();
|
||||
let root = cloned.lock().unwrap();
|
||||
let root_style = root.deref().style();
|
||||
let root_layout = root_style.layout.to_owned();
|
||||
let taffy_root_node = taffy.new_leaf(root_layout).unwrap();
|
||||
|
|
@ -241,7 +242,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
let width: NonZeroU32 = NonZeroU32::new(size.width).unwrap();
|
||||
let height: NonZeroU32 = NonZeroU32::new(size.height).unwrap();
|
||||
surface.resize(&buffer_context, width, height);
|
||||
let mut groot = entry.root.write().unwrap();
|
||||
let mut groot = entry.root.lock().unwrap();
|
||||
// let scale_factor = window.scale_factor();
|
||||
groot.resize(size.width as f32, size.height as f32);
|
||||
drop(groot);
|
||||
|
|
@ -263,7 +264,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
}
|
||||
prepare_render_recursively(&root, &mut context);
|
||||
for (node, taffy_node) in context.node_layout.iter() {
|
||||
let node = node.read().unwrap();
|
||||
let node = node.lock().unwrap();
|
||||
let node_style = node.style();
|
||||
context.taffy.set_style(*taffy_node, node_style.layout.to_owned()).unwrap();
|
||||
}
|
||||
|
|
@ -279,7 +280,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
Some(node) => {
|
||||
match node.upgrade() {
|
||||
Some(node) => {
|
||||
node.write().unwrap().measure(&mut measure_context, known_dimensions, available_space)
|
||||
node.lock().unwrap().measure(&mut measure_context, known_dimensions, available_space)
|
||||
},
|
||||
None => Size::ZERO
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@ pub struct Image {
|
|||
pub style: Style,
|
||||
/// The image to be rendered.
|
||||
pub image: ImageLoad,
|
||||
/// Border radius
|
||||
pub radius: f32,
|
||||
pub events: EventHandlerDatabase,
|
||||
pub parent: Option<WeakNode>
|
||||
}
|
||||
|
|
@ -58,10 +56,6 @@ impl Image {
|
|||
..Default::default()
|
||||
}
|
||||
}
|
||||
pub fn radius(mut self, radius: f32) -> Image {
|
||||
self.radius = radius;
|
||||
self
|
||||
}
|
||||
pub fn style(mut self, style: Style) -> Image {
|
||||
self.style = style;
|
||||
self
|
||||
|
|
@ -123,10 +117,13 @@ impl Node for Image {
|
|||
0.,
|
||||
layout.size.width,
|
||||
layout.size.height,
|
||||
self.radius
|
||||
self.style.border_radius
|
||||
);
|
||||
match &self.image {
|
||||
ImageLoad::Loaded(image) => {
|
||||
if let Some(background) = &self.style.background {
|
||||
context.canvas.fill_path(&path, background);
|
||||
}
|
||||
context.canvas.fill_path(
|
||||
&path,
|
||||
&Paint::image(image.image, 0., 0., layout.size.width, layout.size.height, 0., 1.)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
use std::fmt::{Debug, Formatter};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use femtovg::{Paint, Path};
|
||||
use crate::{nodes::{Node, NodeChildren, Style}, events::handler::EventHandlerDatabase, WeakNode, SharedNode};
|
||||
use taffy::style::Dimension;
|
||||
use crate::nodes::primitives::draw_rect;
|
||||
use crate::nodes::RenderContext;
|
||||
|
||||
/// A simple layout node which contains children.
|
||||
#[derive(Default)]
|
||||
|
|
@ -18,7 +21,7 @@ impl Layout {
|
|||
style: Style::default(),
|
||||
children,
|
||||
events: EventHandlerDatabase::default(),
|
||||
parent: None
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
pub fn empty() -> Layout {
|
||||
|
|
@ -26,7 +29,7 @@ impl Layout {
|
|||
style: Style::default(),
|
||||
children: NodeChildren::default(),
|
||||
events: EventHandlerDatabase::default(),
|
||||
parent: None
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +59,10 @@ impl Node for Layout {
|
|||
self.style.layout.size.width = Dimension::Length(width);
|
||||
self.style.layout.size.height = Dimension::Length(height);
|
||||
}
|
||||
|
||||
fn render_pre_children(&mut self, context: &mut RenderContext, layout: taffy::Layout) {
|
||||
if let Some(background) = &self.style.background { draw_rect(layout.size, background, self.style.border_radius, &mut context.canvas); }
|
||||
}
|
||||
|
||||
fn add_child_at(&mut self, child: crate::SharedNode, index: usize) -> Result<(), super::ChildAddError> {
|
||||
let mut index = index;
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@ pub mod text;
|
|||
pub mod text_render_cache;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use femtovg::{Canvas, Color};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use femtovg::{Canvas, Color, Paint};
|
||||
use crate::events::Location;
|
||||
use crate::events::handler::InnerEventHandlerDataset;
|
||||
use crate::{NodeLayoutMap, NodePtr, CurrentRenderer, SharedNode, WeakNode};
|
||||
|
||||
pub use taffy::style::Style as TaffyStyle;
|
||||
use taffy::{Layout, Overflow, Size, TaffyTree};
|
||||
use taffy::{Layout, Overflow, Point, Size, TaffyTree};
|
||||
|
||||
pub type CanvasRenderer = Canvas<CurrentRenderer>;
|
||||
|
||||
|
|
@ -38,9 +38,9 @@ impl RenderContext {
|
|||
pub fn fill_rect(&mut self, x: u32, y: u32, width: u32, height: u32, color: Color) {
|
||||
let transform = self.canvas.transform();
|
||||
let x = transform[0] * x as f32 + transform[2] * y as f32 + transform[4];
|
||||
let y = transform[1] * x as f32 + transform[3] * y as f32 + transform[5];
|
||||
let y = transform[1] * x + transform[3] * y as f32 + transform[5];
|
||||
let width = transform[0] * width as f32 + transform[2] * height as f32;
|
||||
let height = transform[1] * width as f32 + transform[3] * height as f32;
|
||||
let height = transform[1] * width + transform[3] * height as f32;
|
||||
self.canvas.clear_rect(x as u32, y as u32, width as u32, height as u32, color);
|
||||
}
|
||||
}
|
||||
|
|
@ -50,10 +50,34 @@ pub enum Cursor {
|
|||
#[default]
|
||||
Default
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
/// Transform is handled by UI lib - components shouldn't need to read this.
|
||||
pub struct Transform {
|
||||
/// Translation in x and y direction (in pixels; scaled by parents)
|
||||
pub position: Point<f32>,
|
||||
/// Scale in x and y direction
|
||||
pub scale: Size<f32>,
|
||||
/// Rotation in radians
|
||||
pub rotation: f32
|
||||
}
|
||||
|
||||
/// Styles for the node. Note that the styles aren't inherited (yet?)
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct Style {
|
||||
pub layout: TaffyStyle,
|
||||
pub cursor: Cursor
|
||||
pub cursor: Cursor,
|
||||
pub background: Option<Paint>,
|
||||
/// defaults to black
|
||||
pub text_fill: Option<Paint>,
|
||||
/// font size in pixels. Default is 16
|
||||
pub font_size: Option<f32>,
|
||||
/// multiplier of line height in relation to font size. Default is 1.2
|
||||
pub line_height: Option<f32>,
|
||||
/// border radius in pixels
|
||||
pub border_radius: f32,
|
||||
/// Various transformation (position, scale and rotation)
|
||||
pub transform: Option<Transform>
|
||||
}
|
||||
|
||||
type NodeChildren = Vec<SharedNode>;
|
||||
|
|
@ -105,7 +129,7 @@ pub enum ChildAddError {
|
|||
/// - [`Node::render_pre_children`] is called
|
||||
/// - children are rendered
|
||||
/// - [`Node::render_post_children`] is called
|
||||
pub trait Node: Debug {
|
||||
pub trait Node: Debug + Send {
|
||||
/// Return style.
|
||||
///insert
|
||||
/// If you're using [`Style`] in your struct directly, your implementation can be as simple as:
|
||||
|
|
@ -172,7 +196,7 @@ pub trait Node: Debug {
|
|||
/// Add a child to the node at the given index. If the node does not support children, returns error ChildrenNotSupported.
|
||||
/// Adding the same child multiple times or to multiple parents is not supported and will result in undefined behavior.
|
||||
/// Arc<RwLock<Node>> does **NOT** mean that it's safe to add the same node multiple times.
|
||||
///
|
||||
///
|
||||
/// Note that this doesn't set the parent of the child. You need to do that manually.
|
||||
///
|
||||
/// Implementors can check [`Node::has_child`] to check if the child already exists. Default implementation throws [`ChildAddError::ChildrenNotSupported`].
|
||||
|
|
@ -275,7 +299,7 @@ pub trait ToShared {
|
|||
|
||||
impl<T: Node + 'static> ToShared for T {
|
||||
fn to_shared(self) -> SharedNode {
|
||||
Arc::new(RwLock::new(self))
|
||||
Arc::new(Mutex::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -283,7 +307,7 @@ impl<T: Node + 'static> ToShared for T {
|
|||
/// The target element should be the last one in path (event handlers are ran in reverse order)
|
||||
pub(crate) fn run_event_handlers(path: Vec<SharedNode>, event: crate::events::NodeEvent) {
|
||||
for node in path.iter().rev() {
|
||||
let node = node.read().unwrap();
|
||||
let node = node.lock().unwrap();
|
||||
if let Some(handlers) = node.event_handlers() {
|
||||
drop(node);
|
||||
for handler in handlers.lock().unwrap().values_mut() {
|
||||
|
|
@ -294,7 +318,7 @@ pub(crate) fn run_event_handlers(path: Vec<SharedNode>, event: crate::events::No
|
|||
}
|
||||
|
||||
pub(crate) fn run_single_event_handlers(node: SharedNode, event: crate::events::NodeEvent) {
|
||||
let node = node.read().unwrap();
|
||||
let node = node.lock().unwrap();
|
||||
if let Some(handlers) = node.event_handlers() {
|
||||
drop(node);
|
||||
for handler in handlers.lock().unwrap().values_mut() {
|
||||
|
|
@ -305,7 +329,7 @@ pub(crate) fn run_single_event_handlers(node: SharedNode, event: crate::events::
|
|||
|
||||
/// Attempts to get path to the element at the target location. Assumes elements are always inside their parents.
|
||||
pub(crate) fn get_element_at(node: &SharedNode, context: &RenderContext, location: Location) -> Option<Vec<SharedNode>> {
|
||||
let node_borrowed = node.read().unwrap();
|
||||
let node_borrowed = node.lock().unwrap();
|
||||
let children = node_borrowed.children();
|
||||
let taffy_node = context.node_layout.get(node);
|
||||
let taffy_node = match taffy_node {
|
||||
|
|
@ -340,7 +364,7 @@ pub(crate) fn update_taffynode_children(node: &SharedNode, context: &mut RenderC
|
|||
Some(taffy_node) => taffy_node,
|
||||
None => {
|
||||
let taffy_node = context.taffy.new_leaf_with_context(
|
||||
node.read().unwrap().style().layout.to_owned(),
|
||||
node.lock().unwrap().style().layout.to_owned(),
|
||||
Arc::downgrade(node)
|
||||
).unwrap();
|
||||
context.node_layout.insert(node.clone(), taffy_node);
|
||||
|
|
@ -350,13 +374,13 @@ pub(crate) fn update_taffynode_children(node: &SharedNode, context: &mut RenderC
|
|||
|
||||
let taffy_node = taffy_node.to_owned();
|
||||
|
||||
match node.read().unwrap().children() {
|
||||
match node.lock().unwrap().children() {
|
||||
None => {},
|
||||
Some(children) => {
|
||||
let mut t_children = Vec::with_capacity(children.len());
|
||||
for child in children {
|
||||
t_children.push(update_taffynode_children(child, context).to_owned());
|
||||
child.write().unwrap().set_parent(Some(Arc::downgrade(node)));
|
||||
child.lock().unwrap().set_parent(Some(Arc::downgrade(node)));
|
||||
}
|
||||
context.taffy.set_children(taffy_node, t_children.as_slice()).unwrap();
|
||||
}
|
||||
|
|
@ -366,13 +390,18 @@ pub(crate) fn update_taffynode_children(node: &SharedNode, context: &mut RenderC
|
|||
}
|
||||
|
||||
pub(crate) fn render_recursively(node: &SharedNode, context: &mut RenderContext) {
|
||||
let read_node = node.read().unwrap();
|
||||
let read_node = node.lock().unwrap();
|
||||
let styles = read_node.style();
|
||||
let taffy_node = context.node_layout.get(node).unwrap();
|
||||
let layout = *context.taffy.layout(*taffy_node).unwrap();
|
||||
let sself = node.clone();
|
||||
context.canvas.save();
|
||||
context.canvas.translate(layout.location.x, layout.location.y);
|
||||
let offset = styles.transform.as_ref().map(|t| (t.position.x, t.position.y)).unwrap_or((0., 0.));
|
||||
context.canvas.translate(layout.location.x + offset.0, layout.location.y + offset.1);
|
||||
if let Some(transform) = &styles.transform {
|
||||
context.canvas.scale(transform.scale.width, transform.scale.height);
|
||||
context.canvas.rotate(transform.rotation);
|
||||
}
|
||||
let clip_width = matches!(styles.layout.overflow.x, Overflow::Hidden | Overflow::Clip);
|
||||
let clip_height = matches!(styles.layout.overflow.y, Overflow::Hidden | Overflow::Clip);
|
||||
if clip_width || clip_height {
|
||||
|
|
@ -384,18 +413,18 @@ pub(crate) fn render_recursively(node: &SharedNode, context: &mut RenderContext)
|
|||
);
|
||||
}
|
||||
drop(read_node);
|
||||
sself.write().unwrap().render_pre_children(context, layout);
|
||||
if let Some(children) = sself.read().unwrap().children() {
|
||||
sself.lock().unwrap().render_pre_children(context, layout);
|
||||
if let Some(children) = sself.lock().unwrap().children() {
|
||||
for child in children {
|
||||
render_recursively(child, context);
|
||||
}
|
||||
}
|
||||
sself.write().unwrap().render_post_children(context, layout);
|
||||
sself.lock().unwrap().render_post_children(context, layout);
|
||||
context.canvas.restore();
|
||||
}
|
||||
|
||||
pub(crate) fn prepare_render_recursively(node: &SharedNode, context: &mut RenderContext) {
|
||||
let mut write_node = node.write().unwrap();
|
||||
let mut write_node = node.lock().unwrap();
|
||||
write_node.prepare_render(context);
|
||||
if let Some(children) = write_node.children() {
|
||||
for child in children {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use femtovg::{Color, Paint, Path};
|
||||
use taffy::Layout;
|
||||
use taffy::{Layout, Size};
|
||||
use crate::{nodes::{Node, NodeChildren, RenderContext, Style}, events::handler::EventHandlerDatabase, WeakNode, SharedNode};
|
||||
use crate::nodes::CanvasRenderer;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Rectangle {
|
||||
pub style: Style,
|
||||
pub fill: Paint,
|
||||
pub radius: f32,
|
||||
pub events: EventHandlerDatabase,
|
||||
pub parent: Option<WeakNode>
|
||||
}
|
||||
|
|
@ -15,8 +14,6 @@ impl Rectangle {
|
|||
pub fn new() -> Rectangle {
|
||||
Rectangle {
|
||||
style: Style::default(),
|
||||
fill: Paint::color(Color::rgb(0, 0, 0)),
|
||||
radius: 0.,
|
||||
events: EventHandlerDatabase::default(),
|
||||
parent: None
|
||||
}
|
||||
|
|
@ -31,18 +28,7 @@ impl Node for Rectangle {
|
|||
None
|
||||
}
|
||||
fn render_pre_children(&mut self, context: &mut RenderContext, layout: Layout) {
|
||||
let mut path = Path::new();
|
||||
path.rounded_rect(
|
||||
0.,
|
||||
0.,
|
||||
layout.size.width,
|
||||
layout.size.height,
|
||||
self.radius
|
||||
);
|
||||
context.canvas.fill_path(
|
||||
&path,
|
||||
&self.fill
|
||||
);
|
||||
draw_rect(layout.size, self.style.background.as_ref().unwrap_or(&Paint::color(Color::black())), self.style.border_radius, &mut context.canvas);
|
||||
}
|
||||
fn event_handlers(&self) -> Option<crate::events::handler::InnerEventHandlerDataset> {
|
||||
Some(self.events.handlers.clone())
|
||||
|
|
@ -56,4 +42,19 @@ impl Node for Rectangle {
|
|||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_rect(size: Size<f32>, fill: &Paint, radius: f32, canvas: &mut CanvasRenderer) {
|
||||
let mut path = Path::new();
|
||||
path.rounded_rect(
|
||||
0.,
|
||||
0.,
|
||||
size.width,
|
||||
size.height,
|
||||
radius
|
||||
);
|
||||
canvas.fill_path(
|
||||
&path,
|
||||
fill
|
||||
);
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
use std::fmt::Debug;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use crate::{events::handler::EventHandlerDatabase, SharedNode, WeakNode, FONT_SYSTEM};
|
||||
use super::{text_render_cache::RENDER_CACHE, Node, NodeChildren, Style, MeasureContext, RenderContext};
|
||||
use cosmic_text::{Attrs, Buffer, Family, Metrics, Shaping, Stretch};
|
||||
use femtovg::{Color, Paint, Path};
|
||||
use cosmic_text::{Attrs, Buffer, Metrics, Shaping};
|
||||
use taffy::{AvailableSpace, Size};
|
||||
use femtovg::{Color, Paint, Path};
|
||||
use crate::nodes::primitives::draw_rect;
|
||||
use crate::nodes::text_render_cache::TextConfig;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
@ -13,16 +13,13 @@ pub struct Text {
|
|||
pub text: String,
|
||||
pub events: EventHandlerDatabase,
|
||||
pub parent: Option<WeakNode>,
|
||||
pub metrics: Metrics,
|
||||
pub buffer: Option<Buffer>,
|
||||
pub paint: Paint
|
||||
pub buffer: Option<Buffer>
|
||||
}
|
||||
|
||||
impl Text {
|
||||
pub fn new(text: String, metrics: Metrics) -> Text {
|
||||
Text {
|
||||
text,
|
||||
metrics,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
@ -30,18 +27,18 @@ impl Text {
|
|||
self.text = text;
|
||||
self
|
||||
}
|
||||
pub fn metrics(mut self, metrics: Metrics) -> Self {
|
||||
self.metrics = metrics;
|
||||
self
|
||||
}
|
||||
pub fn paint(mut self, paint: Paint) -> Self {
|
||||
self.paint = paint;
|
||||
self
|
||||
}
|
||||
pub fn style(mut self, style: Style) -> Self {
|
||||
self.style = style;
|
||||
self
|
||||
}
|
||||
|
||||
fn get_metrics(&self) -> Metrics {
|
||||
let fontSize = self.style.font_size.unwrap_or(16.);
|
||||
Metrics {
|
||||
font_size: fontSize,
|
||||
line_height: fontSize * self.style.line_height.unwrap_or(1.2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for Text {
|
||||
|
|
@ -55,7 +52,7 @@ impl Node for Text {
|
|||
|
||||
fn prepare_render(&mut self, _context: &mut RenderContext) {
|
||||
if let None = self.buffer {
|
||||
self.buffer = Some(Buffer::new(&mut FONT_SYSTEM.lock().unwrap(), self.metrics));
|
||||
self.buffer = Some(Buffer::new(&mut FONT_SYSTEM.lock().unwrap(), self.get_metrics()));
|
||||
}
|
||||
let buf = self.buffer.as_mut().unwrap();
|
||||
let mut font = FONT_SYSTEM.lock().unwrap();
|
||||
|
|
@ -63,6 +60,8 @@ impl Node for Text {
|
|||
}
|
||||
|
||||
fn render_pre_children(&mut self, context: &mut super::RenderContext, layout: taffy::prelude::Layout) {
|
||||
if let Some(background) = &self.style.background { draw_rect(layout.size, background, self.style.border_radius, &mut context.canvas); }
|
||||
let metrics = self.get_metrics();
|
||||
// this can crash, but it should crash earlier during measure -> see the comment there.
|
||||
let buf = self.buffer.as_mut().unwrap();
|
||||
let mut font = FONT_SYSTEM.lock().unwrap();
|
||||
|
|
@ -72,41 +71,17 @@ impl Node for Text {
|
|||
);
|
||||
// the height * scale factor is an ugly hack to fix height of the text... not sure why it's wrong in the first place
|
||||
buf.set_size(&mut font, layout.content_size.width - offset_size.0, (layout.content_size.height * context.scale_factor) - offset_size.1);
|
||||
buf.set_metrics(&mut font, self.metrics.scale(context.scale_factor));
|
||||
buf.set_metrics(&mut font, metrics.scale(context.scale_factor));
|
||||
// fill_to_cmds requires FONT_SYSTEM lock.
|
||||
drop(font);
|
||||
let mut path = Path::new();
|
||||
path.rounded_rect(
|
||||
0.,
|
||||
0.,
|
||||
layout.size.width,
|
||||
layout.size.height,
|
||||
0.
|
||||
);
|
||||
context.canvas.fill_path(
|
||||
&path,
|
||||
&Paint::color(Color::rgb(255, 0, 0))
|
||||
);
|
||||
let position = (
|
||||
layout.padding.left + layout.border.left,
|
||||
layout.padding.top + layout.border.top
|
||||
);
|
||||
let mut path = Path::new();
|
||||
path.rounded_rect(
|
||||
position.0,
|
||||
position.1,
|
||||
layout.content_size.width - offset_size.0,
|
||||
layout.content_size.height - offset_size.1,
|
||||
0.
|
||||
);
|
||||
context.canvas.fill_path(
|
||||
&path,
|
||||
&Paint::color(Color::rgb(0, 0, 255))
|
||||
);
|
||||
let cmds = RENDER_CACHE.lock().unwrap()
|
||||
.fill_to_cmds(&mut context.canvas, buf, position, context.scale_factor, TextConfig { hint: false, subpixel: false })
|
||||
.unwrap();
|
||||
context.canvas.draw_glyph_commands(cmds, &self.paint, context.scale_factor);
|
||||
context.canvas.draw_glyph_commands(cmds, self.style.text_fill.as_ref().unwrap_or(&Paint::color(Color::black())), context.scale_factor);
|
||||
}
|
||||
|
||||
fn measure(&mut self, context: &mut MeasureContext, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>) -> Size<f32> {
|
||||
|
|
@ -115,12 +90,13 @@ impl Node for Text {
|
|||
AvailableSpace::MaxContent => f32::INFINITY,
|
||||
AvailableSpace::Definite(width) => width,
|
||||
});
|
||||
let metrics = self.get_metrics();
|
||||
// yes, this can crash if someone removes `buffer` during render from another thread.
|
||||
// though they're asking for it, so let them crash.
|
||||
let buf = self.buffer.as_mut().unwrap();
|
||||
let mut font = FONT_SYSTEM.lock().unwrap();
|
||||
buf.set_size(&mut font, width_constraint, f32::INFINITY);
|
||||
buf.set_metrics(&mut font, self.metrics.scale(context.scale_factor));
|
||||
buf.set_metrics(&mut font, metrics.scale(context.scale_factor));
|
||||
|
||||
// Compute layout
|
||||
buf.shape_until_scroll(&mut font, true);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,85 @@
|
|||
use proc_macro2::{Span, TokenStream, TokenTree};
|
||||
use quote::{IdentFragment, quote_spanned};
|
||||
use quote::{IdentFragment, quote, quote_spanned, ToTokens};
|
||||
use quote::spanned::Spanned;
|
||||
|
||||
macro_rules! impl_enum_totokens {
|
||||
(
|
||||
$name:ident,
|
||||
$prefix:path
|
||||
$(, $( $variant:ident ),+)?
|
||||
$(; $( $qvariant:ident ( $( $qual:ident ),+ ) ),* )?
|
||||
$(| $( $qvariant2:ident ( $( $qual2:ident => $qtype:tt ),+ ) ),* )?
|
||||
) => {
|
||||
impl ToTokens for $name {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
stream.extend(match self {
|
||||
$(
|
||||
$(
|
||||
$name::$variant => {
|
||||
quote! {
|
||||
$prefix::$variant
|
||||
}
|
||||
}
|
||||
),+
|
||||
)?
|
||||
$(
|
||||
$(
|
||||
$name::$qvariant($($qual),+) => {
|
||||
quote! {
|
||||
$prefix::$qvariant($(#$qual),+)
|
||||
}
|
||||
}
|
||||
)+
|
||||
)?
|
||||
$(
|
||||
$(
|
||||
$name::$qvariant2($($qual2),+) => {
|
||||
quote! {
|
||||
$prefix::$qvariant2($( $qtype ),+)
|
||||
}
|
||||
}
|
||||
)+
|
||||
)?
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_struct_usersettable_totokens {
|
||||
(
|
||||
$name:ident,
|
||||
$prefix:path,
|
||||
$($variant:ident),+
|
||||
$(| $( $qvariant:ident => $qtype:tt ),* )?
|
||||
) => {
|
||||
impl ToTokens for $name {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
let $name { $($variant),+, .. } = self;
|
||||
let mut substream = TokenStream::new();
|
||||
$(
|
||||
if !$variant.is_empty() {
|
||||
substream.extend(quote! { $variant: #$variant, });
|
||||
}
|
||||
)+
|
||||
$(
|
||||
$(
|
||||
if !$qvariant.is_empty() {
|
||||
substream.extend(quote! { $qvariant: #$qtype, });
|
||||
}
|
||||
),*
|
||||
)?
|
||||
stream.extend(quote! {
|
||||
$prefix {
|
||||
#substream
|
||||
..Default::default()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum UserSettable<T> {
|
||||
Value(T),
|
||||
|
|
@ -28,6 +106,14 @@ impl<T> UserSettable<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
UserSettable::Value(_) => false,
|
||||
UserSettable::Arbitrary(_) => false,
|
||||
UserSettable::None => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> UserSettable<T> {
|
||||
|
|
@ -48,18 +134,79 @@ impl<T: Default> UserSettable<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ToTokens> ToTokens for UserSettable<T> {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
stream.extend(match self {
|
||||
UserSettable::Value(value) => value.to_token_stream(),
|
||||
UserSettable::Arbitrary(stream) => stream.clone(),
|
||||
UserSettable::None => quote! { Default::default() }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct Point<T> {
|
||||
x: UserSettable<T>,
|
||||
y: UserSettable<T>
|
||||
}
|
||||
|
||||
impl<T: ToTokens> ToTokens for Point<T> {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
let Point { x, y } = self;
|
||||
stream.extend(quote! {
|
||||
mangui::taffy::Point { x: #x, y: #y }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct Size<T> {
|
||||
width: UserSettable<T>,
|
||||
height: UserSettable<T>
|
||||
}
|
||||
|
||||
impl<T: ToTokens> ToTokens for Size<T> {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
let Size { width, height } = self;
|
||||
stream.extend(quote! {
|
||||
mangui::taffy::Size { width: #width, height: #height }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct Rect<T> {
|
||||
pub left: UserSettable<T>,
|
||||
pub right: UserSettable<T>,
|
||||
pub top: UserSettable<T>,
|
||||
pub bottom: UserSettable<T>,
|
||||
}
|
||||
|
||||
impl<T: ToTokens> ToTokens for Rect<T> {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
let Rect { left, right, top, bottom } = self;
|
||||
let mut substream = TokenStream::new();
|
||||
if !left.is_empty() {
|
||||
substream.extend(quote! { left: #left, });
|
||||
}
|
||||
if !right.is_empty() {
|
||||
substream.extend(quote! { right: #right, });
|
||||
}
|
||||
if !top.is_empty() {
|
||||
substream.extend(quote! { top: #top, });
|
||||
}
|
||||
if !bottom.is_empty() {
|
||||
substream.extend(quote! { bottom: #bottom, });
|
||||
}
|
||||
if left.is_empty() || right.is_empty() || top.is_empty() || bottom.is_empty() {
|
||||
substream.extend(quote! { ..Rect::zero() });
|
||||
}
|
||||
stream.extend(quote! {
|
||||
mangui::taffy::geometry::Rect { #substream }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct Color {
|
||||
r: f32,
|
||||
|
|
@ -68,6 +215,15 @@ struct Color {
|
|||
a: f32
|
||||
}
|
||||
|
||||
impl ToTokens for Color {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
let Color { r, g, b, a } = self;
|
||||
stream.extend(quote! {
|
||||
mangui::femtovg::Color::rgba(#r, #g, #b, #a)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Paint {
|
||||
Color(Color)
|
||||
|
|
@ -84,12 +240,26 @@ impl Default for Paint {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Paint {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
stream.extend(match self {
|
||||
Paint::Color(color) => {
|
||||
quote! {
|
||||
mangui::femtovg::Paint::color(#color)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug)]
|
||||
enum Cursor {
|
||||
#[default]
|
||||
Default
|
||||
}
|
||||
|
||||
impl_enum_totokens!(Cursor, mangui::femtovg::Cursor, Default);
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct Transform {
|
||||
pub position: UserSettable<Point<f32>>,
|
||||
|
|
@ -97,6 +267,8 @@ struct Transform {
|
|||
pub rotation: UserSettable<f32>
|
||||
}
|
||||
|
||||
impl_struct_usersettable_totokens!(Transform, mangui::nodes::Transform, position, scale, rotation);
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct Style {
|
||||
pub layout: UserSettable<TaffyStyle>,
|
||||
|
|
@ -109,13 +281,11 @@ struct Style {
|
|||
pub transform: UserSettable<Transform>
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct Rect<T> {
|
||||
pub left: UserSettable<T>,
|
||||
pub right: UserSettable<T>,
|
||||
pub top: UserSettable<T>,
|
||||
pub bottom: UserSettable<T>,
|
||||
}
|
||||
impl_struct_usersettable_totokens!(
|
||||
Style,
|
||||
mangui::nodes::Style,
|
||||
layout, cursor, background, text_fill, font_size, line_height, border_radius, transform
|
||||
);
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum Position {
|
||||
|
|
@ -124,6 +294,8 @@ enum Position {
|
|||
Absolute,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(Position, mangui::taffy::Position, Relative, Absolute);
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum Display {
|
||||
Block,
|
||||
|
|
@ -133,6 +305,8 @@ enum Display {
|
|||
None,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(Display, mangui::taffy::Display, Block, Flex, Grid, None);
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum Overflow {
|
||||
#[default]
|
||||
|
|
@ -142,6 +316,8 @@ enum Overflow {
|
|||
Scroll,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(Overflow, mangui::taffy::Overflow, Visible, Clip, Hidden, Scroll);
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum LengthPercentageAuto {
|
||||
Length(f32),
|
||||
|
|
@ -150,6 +326,8 @@ enum LengthPercentageAuto {
|
|||
Auto,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(LengthPercentageAuto, mangui::taffy::LengthPercentageAuto, Auto; Length(i), Percent(i));
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum Dimension {
|
||||
Length(f32),
|
||||
|
|
@ -158,12 +336,16 @@ enum Dimension {
|
|||
Auto,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(Dimension, mangui::taffy::Dimension, Auto; Length(i), Percent(i));
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum LengthPercentage {
|
||||
Length(f32),
|
||||
Percent(f32),
|
||||
}
|
||||
|
||||
impl_enum_totokens!(LengthPercentage, mangui::taffy::LengthPercentage; Length(i), Percent(i));
|
||||
|
||||
impl Default for LengthPercentage {
|
||||
fn default() -> Self {
|
||||
LengthPercentage::Length(0.)
|
||||
|
|
@ -181,6 +363,8 @@ enum AlignItems {
|
|||
Stretch,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(AlignItems, mangui::taffy::AlignItems, Start, End, FlexStart, FlexEnd, Center, Baseline, Stretch);
|
||||
|
||||
type AlignSelf = AlignItems;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -197,6 +381,8 @@ enum AlignContent {
|
|||
}
|
||||
type JustifyContent = AlignContent;
|
||||
|
||||
impl_enum_totokens!(AlignContent, mangui::taffy::AlignContent, Start, End, FlexStart, FlexEnd, Center, Stretch, SpaceBetween, SpaceEvenly, SpaceAround);
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum FlexDirection {
|
||||
#[default]
|
||||
|
|
@ -206,6 +392,8 @@ enum FlexDirection {
|
|||
ColumnReverse,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(FlexDirection, mangui::taffy::FlexDirection, Row, Column, RowReverse, ColumnReverse);
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum FlexWrap {
|
||||
#[default]
|
||||
|
|
@ -214,6 +402,8 @@ enum FlexWrap {
|
|||
WrapReverse,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(FlexWrap, mangui::taffy::FlexWrap, NoWrap, Wrap, WrapReverse);
|
||||
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct Line<T> {
|
||||
|
|
@ -221,11 +411,30 @@ struct Line<T> {
|
|||
pub end: T,
|
||||
}
|
||||
|
||||
impl<T: ToTokens> ToTokens for Line<T> {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
let Line { start, end } = self;
|
||||
stream.extend(quote! {
|
||||
mangui::taffy::Line::new(#start, #end)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct MinMax<Min, Max> {
|
||||
pub min: Min,
|
||||
pub max: Max,
|
||||
}
|
||||
|
||||
impl<Min: ToTokens, Max: ToTokens> ToTokens for MinMax<Min, Max> {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
let MinMax { min, max } = self;
|
||||
stream.extend(quote! {
|
||||
mangui::taffy::MinMax::new(#min, #max)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum MinTrackSizingFunction {
|
||||
Fixed(LengthPercentage),
|
||||
|
|
@ -233,6 +442,9 @@ enum MinTrackSizingFunction {
|
|||
MaxContent,
|
||||
Auto,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(MinTrackSizingFunction, mangui::taffy::MinTrackSizingFunction, MinContent, MaxContent, Auto; Fixed(i));
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum MaxTrackSizingFunction {
|
||||
Fixed(LengthPercentage),
|
||||
|
|
@ -243,6 +455,9 @@ enum MaxTrackSizingFunction {
|
|||
Fraction(f32),
|
||||
}
|
||||
type NonRepeatedTrackSizingFunction = MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>;
|
||||
|
||||
impl_enum_totokens!(MaxTrackSizingFunction, mangui::taffy::MaxTrackSizingFunction, MinContent, MaxContent, Auto; FitContent(i), Fraction(i), Fixed(i));
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum GridTrackRepetition {
|
||||
AutoFill,
|
||||
|
|
@ -250,12 +465,16 @@ enum GridTrackRepetition {
|
|||
Count(u16),
|
||||
}
|
||||
|
||||
impl_enum_totokens!(GridTrackRepetition, mangui::taffy::GridTrackRepetition, AutoFill, AutoFit; Count(i));
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum TrackSizingFunction {
|
||||
Single(NonRepeatedTrackSizingFunction),
|
||||
Repeat(GridTrackRepetition, Vec<NonRepeatedTrackSizingFunction>),
|
||||
}
|
||||
|
||||
impl_enum_totokens!(TrackSizingFunction, mangui::taffy::TrackSizingFunction; Single(i) | Repeat(repeat => (#repeat), functions => (vec![#( #functions ),*])));
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum GridAutoFlow {
|
||||
#[default]
|
||||
|
|
@ -265,8 +484,20 @@ enum GridAutoFlow {
|
|||
ColumnDense,
|
||||
}
|
||||
|
||||
impl_enum_totokens!(GridAutoFlow, mangui::taffy::GridAutoFlow, Row, Column, RowDense, ColumnDense);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct GridLine(i16);
|
||||
|
||||
impl ToTokens for GridLine {
|
||||
fn to_tokens(&self, stream: &mut TokenStream) {
|
||||
let GridLine(line) = self;
|
||||
stream.extend(quote! {
|
||||
mangui::taffy::GridLine::new(#line)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
enum GridPlacement {
|
||||
#[default]
|
||||
|
|
@ -274,6 +505,10 @@ enum GridPlacement {
|
|||
Line(GridLine),
|
||||
Span(u16),
|
||||
}
|
||||
|
||||
impl_enum_totokens!(GridPlacement, mangui::taffy::GridPlacement, Auto; Line(i), Span(i));
|
||||
|
||||
/// Styles for positioning. Note that grid template rows/columns and auto rows/columns are not supported yet (generated)
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct TaffyStyle {
|
||||
pub display: UserSettable<Display>,
|
||||
|
|
@ -309,6 +544,17 @@ struct TaffyStyle {
|
|||
pub grid_column: UserSettable<Line<GridPlacement>>,
|
||||
}
|
||||
|
||||
impl_struct_usersettable_totokens!(
|
||||
TaffyStyle,
|
||||
mangui::taffy::Style,
|
||||
display, overflow, scrollbar_width, position, inset, size, min_size, max_size,
|
||||
aspect_ratio, margin, padding, border,
|
||||
align_items, align_self, justify_items, justify_self, align_content, justify_content,
|
||||
gap,
|
||||
flex_direction, flex_wrap, flex_basis, flex_grow, flex_shrink,
|
||||
grid_auto_flow, grid_row, grid_column
|
||||
);
|
||||
|
||||
trait ValueToUserSettable<T> {
|
||||
fn to_user_settable(self, span: Span, inverse: bool) -> Result<UserSettable<T>, RuleParseError>;
|
||||
}
|
||||
|
|
@ -479,7 +725,6 @@ struct RuleParseError {
|
|||
#[proc_macro]
|
||||
pub fn uno(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let item = TokenStream::from(item);
|
||||
let mut output = TokenStream::new();
|
||||
dbg!(&item);
|
||||
let rules = parse_rules(item);
|
||||
|
||||
|
|
@ -503,9 +748,9 @@ pub fn uno(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|||
}
|
||||
};
|
||||
|
||||
dbg!(style);
|
||||
dbg!(&style);
|
||||
|
||||
output.into()
|
||||
style.to_token_stream().into()
|
||||
}
|
||||
|
||||
fn process_rules(rules: Vec<Rule>) -> Result<Style, RuleParseError> {
|
||||
|
|
|
|||
Loading…
Reference in a new issue