hobo_css/
properties.rs

1#[macro_use] mod flex;
2#[macro_use] mod margin;
3#[macro_use] mod padding;
4#[macro_use] mod dimensions;
5#[macro_use] mod position;
6#[macro_use] mod text;
7#[macro_use] mod border;
8#[macro_use] mod background;
9#[macro_use] mod svg;
10#[macro_use] mod animation;
11#[macro_use] mod transform;
12#[macro_use] mod filter;
13#[macro_use] mod grid;
14#[macro_use] mod clip_path;
15#[macro_use] mod appearance;
16
17use crate::prelude::*;
18pub use animation::*;
19pub use appearance::*;
20pub use background::*;
21pub use border::*;
22pub use clip_path::*;
23pub use dimensions::*;
24pub use filter::*;
25pub use flex::*;
26pub use grid::*;
27pub use margin::*;
28pub use padding::*;
29pub use position::*;
30pub use svg::*;
31pub use text::*;
32pub use transform::*;
33
34#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
35pub enum ColorValue {
36	Rgba(crate::color::Color),
37	Initial,
38	Inherit,
39	Unset,
40}
41
42#[rustfmt::skip]
43impl std::fmt::Display for ColorValue {
44	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45		match self {
46			Self::Rgba(x)    => x.fmt(f),
47			Self::Initial    => "initial".fmt(f),
48			Self::Inherit    => "inherit".fmt(f),
49			Self::Unset      => "unset".fmt(f),
50		}
51	}
52}
53
54#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
55pub enum UnitValue {
56	Unit(Unit),
57	Initial,
58	Inherit,
59	Unset,
60}
61
62#[rustfmt::skip]
63impl std::fmt::Display for UnitValue {
64	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65		match self {
66			Self::Unit(x) => x.fmt(f),
67			Self::Initial => "initial".fmt(f),
68			Self::Inherit => "inherit".fmt(f),
69			Self::Unset   => "unset".fmt(f),
70		}
71	}
72}
73
74/*
75pub enum RadialGradientShape {
76	Circle,
77	Ellipse,
78	// ???
79}
80
81pub struct RadialGradient {
82	shape: RadialGradientShape,
83	center_point: Vec<[BackgroundPositionElement; 4]>,
84	stop_list: Vec<((u8, u8, u8, u8), Unit)>,
85}
86*/
87
88#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
89pub struct LinearGradient {
90	pub angle: F32,
91	pub stop_list: Vec<(crate::Color, Unit)>,
92}
93
94impl std::fmt::Display for LinearGradient {
95	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96		write!(f, "{}deg", self.angle)?;
97		for (color, stop) in &self.stop_list {
98			write!(f, ",{} {}", color, stop)?;
99		}
100		Ok(())
101	}
102}
103
104#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
105pub enum Image {
106	Url(String),
107	LinearGradient(LinearGradient),
108	RepeatingLinearGradient(LinearGradient),
109	// RadialGradient(RadialGradient),
110	// RepeatingRadialGradient(RadialGradient),
111	// conic ??
112}
113
114impl Image {
115	pub fn url(x: impl Into<String>) -> Self { Self::Url(x.into()) }
116	pub fn linear_gradient(angle: f32, stop_list: Vec<(crate::Color, Unit)>) -> Self { Self::LinearGradient(LinearGradient { angle: F32::new(angle).unwrap(), stop_list }) }
117	pub fn repeating_linear_gradient(angle: f32, stop_list: Vec<(crate::Color, Unit)>) -> Self { Self::RepeatingLinearGradient(LinearGradient { angle: F32::new(angle).unwrap(), stop_list }) }
118}
119
120impl std::fmt::Display for Image {
121	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122		match self {
123			Self::Url(x) => write!(f, r#"url("{}")"#, x),
124			Self::LinearGradient(x) => write!(f, "linear-gradient({})", x),
125			Self::RepeatingLinearGradient(x) => write!(f, "repeating-linear-gradient({})", x),
126		}
127	}
128}
129
130#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
131pub enum BasicShape {
132	Polygon(Vec<(Unit, Unit)>),
133	// etc
134}
135
136impl std::fmt::Display for BasicShape {
137	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138		match self {
139			Self::Polygon(points) => {
140				"polygon(".fmt(f)?;
141				if let Some(((x, y), rest)) = points.split_first() {
142					write!(f, "{} {}", x, y)?;
143					for (x, y) in rest {
144						write!(f, ",{} {}", x, y)?;
145					}
146				}
147				")".fmt(f)
148			},
149		}
150	}
151}
152
153macro_rules! generate_properties {
154	(
155		stutter => ($($stutter_name:ident),*$(,)?),
156		named => ($($css_name:expr => $named_name:ident($named_type:ty)),*$(,)?),
157	) => {
158		pub use Property::{$($named_name),*};
159
160		#[allow(clippy::derive_ord_xor_partial_ord)]
161		#[derive(Debug, PartialEq, Eq, Hash, Clone, strum::EnumDiscriminants, Ord)]
162		#[strum_discriminants(derive(PartialOrd))]
163		pub enum Property {
164			Raw(String),
165			$($stutter_name($stutter_name),)*
166			$($named_name($named_type)),*
167		}
168
169		impl std::cmp::PartialOrd for Property {
170			fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
171				PropertyDiscriminants::from(self).partial_cmp(&PropertyDiscriminants::from(other))
172			}
173		}
174
175		impl std::fmt::Display for Property {
176			fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177				match self {
178					Self::Raw(x) => x.fmt(f),
179					$(Self::$named_name(x) => write!(f, "{}:{};", $css_name, x),)*
180					$(Self::$stutter_name(x) => x.fmt(f)),*
181				}
182			}
183		}
184
185		$(
186			impl From<$stutter_name> for Property {
187				fn from(x: $stutter_name) -> Self { Self::$stutter_name(x) }
188			}
189
190			impl crate::AppendProperty for $stutter_name {
191				fn append_property(self, decls: &mut Vec<Property>) { decls.push(Property::$stutter_name(self)); }
192			}
193		)*
194	};
195}
196
197// rather than having this huge enum, it might be possible fo just having a Vec of `Box<Display>` or `Box<Property>` with `Property` being a trait
198generate_properties! {
199	// different properties that have specific to them arguments
200	// basis/grow/shrink/order kind of take the same, but basis and shrink are 1 by default while others are 0 so /shrug
201	stutter => (
202		FlexWrap, FlexDirection,
203		JustifyContent, AlignItems, AlignContent, AlignSelf,
204		JustifyItems, JustifySelf,
205		FlexBasis, FlexGrow, FlexShrink,
206
207		Order,
208		Position,
209		Display,
210		BoxSizing,
211		Visibility,
212		ZIndex,
213		OverflowX, OverflowY,
214		Direction,
215		UnicodeBidi,
216		WhiteSpace,
217		WritingMode,
218		HangingPunctuation,
219		Hyphens,
220		TextAlign,
221		TextAlignLast,
222		TextJustify,
223		FontStretch,
224		UserSelect,
225		ScrollBehavior,
226		PointerEvents,
227		TouchAction,
228		Resize,
229		ObjectFit,
230		ListStyleType, ListStyleImage, ListStylePosition,
231
232		BreakAfter, BreakBefore, BreakInside,
233
234		FontVariant,
235		WordBreak,
236		WordWrap,
237		FontStyle,
238		TransformStyle,
239		BackgroundBlendMode,
240		MixBlendMode,
241		Isolation,
242		CaptionSide,
243		EmptyCells,
244		TableLayout,
245		BorderCollapse,
246		All,
247		FontWeight,
248		FontSize,
249		BackgroundRepeat,
250		BackgroundAttachment,
251		Cursor,
252		TextTransform,
253		TextShadow,
254		FontKerning,
255		FontFamily,
256		WordSpacing,
257		TextOverflow,
258		VerticalAlign,
259		LineHeight,
260		LetterSpacing,
261		TabSize,
262		BoxDecorationBreak,
263		OutlineWidth,
264		OutlineStyle,
265		Content,
266		Opacity,
267		Perspective,
268		BackfaceVisibility,
269		TextDecorationStyle,
270		TextDecorationLine,
271		TextRendering,
272		VectorEffect,
273		AlignmentBaseline,
274		DominantBaseline,
275		TextAnchor,
276		StrokeLinecap,
277		BackgroundImage,
278		BackgroundSize,
279
280		AnimationDirection, AnimationFillMode, AnimationIterationCount,
281		AnimationName, AnimationPlayState, AnimationTimingFunction,
282		AnimationDuration, AnimationDelay,
283
284		TransitionProperty, TransitionTimingFunction,
285		TransitionDuration, TransitionDelay,
286
287		Transform,
288		Filter,
289
290		BorderImageSource, BorderImageSlice, BorderImageWidth,
291		BorderImageOutset, BorderImageRepeat,
292
293		ClipPath,
294		BackgroundOrigin,
295		BackgroundClip,
296		GridAutoFlow,
297		RowGap,
298		ColumnGap,
299		GridGap,
300		OverflowWrap,
301		BoxShadow,
302		TransformOrigin,
303		Appearance,
304		MaskImage,
305		MaskSize,
306		Float,
307		Clear,
308		AspectRatio,
309		OverflowAnchor,
310	),
311	// different properties that take the same argument
312	named => (
313		"margin-left" => MarginLeft(Margin),
314		"margin-right" => MarginRight(Margin),
315		"margin-top" => MarginTop(Margin),
316		"margin-bottom" => MarginBottom(Margin),
317
318		"padding-left" => PaddingLeft(UnitValue),
319		"padding-right" => PaddingRight(UnitValue),
320		"padding-top" => PaddingTop(UnitValue),
321		"padding-bottom" => PaddingBottom(UnitValue),
322
323		"width" => Width(DimensionExtremity),
324		"height" => Height(DimensionExtremity),
325		"min-width" => MinWidth(DimensionExtremity),
326		"max-width" => MaxWidth(DimensionExtremity),
327		"min-height" => MinHeight(DimensionExtremity),
328		"max-height" => MaxHeight(DimensionExtremity),
329
330		"top" => Top(Dimension),
331		"right" => Right(Dimension),
332		"left" => Left(Dimension),
333		"bottom" => Bottom(Dimension),
334
335		"border-left-color" => BorderLeftColor(ColorValue),
336		"border-right-color" => BorderRightColor(ColorValue),
337		"border-top-color" => BorderTopColor(ColorValue),
338		"border-bottom-color" => BorderBottomColor(ColorValue),
339
340		"border-left-style" => BorderLeftStyle(BorderStyle),
341		"border-right-style" => BorderRightStyle(BorderStyle),
342		"border-top-style" => BorderTopStyle(BorderStyle),
343		"border-bottom-style" => BorderBottomStyle(BorderStyle),
344
345		"border-left-width" => BorderLeftWidth(BorderWidth),
346		"border-right-width" => BorderRightWidth(BorderWidth),
347		"border-top-width" => BorderTopWidth(BorderWidth),
348		"border-bottom-width" => BorderBottomWidth(BorderWidth),
349
350		"border-top-left-radius" => BorderTopLeftRadius(UnitValue),
351		"border-top-right-radius" => BorderTopRightRadius(UnitValue),
352		"border-bottom-left-radius" => BorderBottomLeftRadius(UnitValue),
353		"border-bottom-right-radius" => BorderBottomRightRadius(UnitValue),
354
355		"background-color" => BackgroundColor(ColorValue),
356		"color" => Color(ColorValue),
357		"text-decoration-color" => TextDecorationColor(ColorValue),
358		"fill" => Fill(ColorValue),
359		"stroke" => Stroke(ColorValue),
360		"stroke-width" => StrokeWidth(UnitValue),
361		"outline-color" => OutlineColor(ColorValue),
362
363		"grid-template-columns" => GridTemplateColumns(GridTemplate),
364		"grid-template-rows" => GridTemplateRows(GridTemplate),
365		"grid-auto-columns" => GridAutoColumns(GridAuto),
366		"grid-auto-rows" => GridAutoRows(GridAuto),
367
368		"text-indent" => TextIndent(UnitValue),
369		"outline-offset" => OutlineOffset(UnitValue),
370
371		"grid-column-start" => GridColumnStart(GridSpan),
372		"grid-column-end" => GridColumnEnd(GridSpan),
373		"grid-row-start" => GridRowStart(GridSpan),
374		"grid-row-end" => GridRowEnd(GridSpan),
375
376		"background-position-x" => BackgroundPositionX(UnitValue),
377		"background-position-y" => BackgroundPositionY(UnitValue),
378	),
379}
380
381crate::macros::easy_enum! {box-sizing content-box border-box}
382crate::macros::easy_enum! {visibility visible hidden collapse}
383crate::macros::easy_enum! {display block none inline inline-block flex inline-flex grid inline-grid flow-root contents table table-row table-row-group table-header-group table-footer-group table-cell table-column-group table-column table-caption list-item}
384// crate::macros::easy_enum! {user-select auto none text all}
385crate::macros::easy_enum! {scroll-behavior auto smooth}
386crate::macros::easy_enum! {pointer-events auto none}
387crate::macros::easy_enum! {touch-action auto none manipulation}
388crate::macros::easy_enum! {resize none both horizontal vertical}
389crate::macros::easy_enum! {object-fit fill contain cover scale-down none}
390crate::macros::easy_enum! {transform-style flat preserve-3d}
391crate::macros::easy_enum! {background-blend-mode normal multiply screen overlay darken lighten color-dodge saturation color luminosity}
392crate::macros::easy_enum! {mix-blend-mode normal multiply screen overlay darken lighten color-dodge color-burn difference exclusion hue saturation color luminosity}
393crate::macros::easy_enum! {isolation auto isolate}
394crate::macros::easy_enum! {caption-side top bottom}
395crate::macros::easy_enum! {empty-cells show hide}
396crate::macros::easy_enum! {table-layout auto fixed}
397crate::macros::easy_enum! {all}
398crate::macros::easy_enum! {cursor auto alias all-scroll cell context-menu col-resize copy crosshair default e-resize ew-resize grab grabbing help move n-resize ne-resize nesw-resize ns-resize nw-resize nwse-resize no-drop none not-allowed pointer progress row-resize s-resize se-resize sw-resize text vertical-text w-resize wait zoom-in zoom-out}
399crate::macros::easy_enum! {content normal none counter open-quote close-quote no-open-quote no-close-quote [string]}
400crate::macros::easy_enum! {opacity [float]}
401crate::macros::easy_enum! {perspective none [unit]}
402crate::macros::easy_enum! {backface-visibility visible hidden}
403crate::macros::easy_enum! {overflow-x visible hidden scroll auto}
404crate::macros::easy_enum! {overflow-y visible hidden scroll auto}
405crate::macros::easy_enum! {float none left right inline-start inline-end}
406crate::macros::easy_enum! {clear none left right inline-start inline-end both}
407crate::macros::easy_enum! {overflow-anchor auto none}
408
409#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd, Ord)]
410pub enum UserSelect {
411	Initial,
412	Inherit,
413	Unset,
414	Auto,
415	None,
416	Text,
417	All,
418}
419
420#[rustfmt::skip]
421impl std::fmt::Display for UserSelect {
422	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
423		match self {
424			Self::Initial => "user-select:initial;-webkit-user-select:initial;-moz-user-select:initial;".fmt(f),
425			Self::Inherit => "user-select:inherit;-webkit-user-select:inherit;-moz-user-select:inherit;".fmt(f),
426			Self::Unset   => "user-select:unset;-webkit-user-select:unset;-moz-user-select:unset;".fmt(f),
427			Self::Auto    => "user-select:auto;-webkit-user-select:auto;-moz-user-select:auto;".fmt(f),
428			Self::None    => "user-select:none;-webkit-user-select:none;-moz-user-select:none;".fmt(f),
429			Self::Text    => "user-select:text;-webkit-user-select:text;-moz-user-select:text;".fmt(f),
430			Self::All     => "user-select:all;-webkit-user-select:all;-moz-user-select:all;".fmt(f),
431		}
432	}
433}
434
435#[macro_export]
436macro_rules! user_select {
437	(initial) => {$crate::Property::UserSelect($crate::UserSelect::Initial)};
438	(inherit) => {$crate::Property::UserSelect($crate::UserSelect::Inherit)};
439	(unset)   => {$crate::Property::UserSelect($crate::UserSelect::Unset)};
440	(auto)    => {$crate::Property::UserSelect($crate::UserSelect::Auto)};
441	(none)    => {$crate::Property::UserSelect($crate::UserSelect::None)};
442	(text)    => {$crate::Property::UserSelect($crate::UserSelect::Text)};
443	(all)     => {$crate::Property::UserSelect($crate::UserSelect::All)};
444}