341 lines
8.4 KiB
Rust
341 lines
8.4 KiB
Rust
use maud::{Markup, Render, html};
|
|
|
|
use crate::ui::UIWidget;
|
|
|
|
use super::Side;
|
|
|
|
#[allow(non_snake_case)]
|
|
pub fn Position<T: UIWidget + 'static>(kind: PositionKind, inner: T) -> Positioned {
|
|
Positioned {
|
|
inner: Box::new(inner),
|
|
kind,
|
|
inset: None,
|
|
inset_x: None,
|
|
inset_y: None,
|
|
start: None,
|
|
end: None,
|
|
top: None,
|
|
right: None,
|
|
bottom: None,
|
|
left: None,
|
|
}
|
|
}
|
|
|
|
pub struct Positioned {
|
|
inner: Box<dyn UIWidget>,
|
|
kind: PositionKind,
|
|
inset: Option<i64>,
|
|
inset_x: Option<i64>,
|
|
inset_y: Option<i64>,
|
|
start: Option<i64>,
|
|
end: Option<i64>,
|
|
top: Option<i64>,
|
|
right: Option<i64>,
|
|
bottom: Option<i64>,
|
|
left: Option<i64>,
|
|
}
|
|
|
|
impl Positioned {
|
|
pub fn inset(mut self, value: i64) -> Self {
|
|
self.inset = Some(value);
|
|
self
|
|
}
|
|
pub fn inset_x(mut self, value: i64) -> Self {
|
|
self.inset_x = Some(value);
|
|
self
|
|
}
|
|
|
|
pub fn inset_y(mut self, value: i64) -> Self {
|
|
self.inset_y = Some(value);
|
|
self
|
|
}
|
|
|
|
pub fn start(mut self, value: i64) -> Self {
|
|
self.start = Some(value);
|
|
self
|
|
}
|
|
|
|
pub fn end(mut self, value: i64) -> Self {
|
|
self.end = Some(value);
|
|
self
|
|
}
|
|
|
|
pub fn top(mut self, value: i64) -> Self {
|
|
self.top = Some(value);
|
|
self
|
|
}
|
|
|
|
pub fn right(mut self, value: i64) -> Self {
|
|
self.right = Some(value);
|
|
self
|
|
}
|
|
|
|
pub fn bottom(mut self, value: i64) -> Self {
|
|
self.bottom = Some(value);
|
|
self
|
|
}
|
|
|
|
pub fn left(mut self, value: i64) -> Self {
|
|
self.left = Some(value);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Render for Positioned {
|
|
fn render(&self) -> Markup {
|
|
self.render_with_class("")
|
|
}
|
|
}
|
|
|
|
impl UIWidget for Positioned {
|
|
fn can_inherit(&self) -> bool {
|
|
true
|
|
}
|
|
|
|
fn base_class(&self) -> Vec<String> {
|
|
let mut ret = vec![self.kind.to_value().to_string()];
|
|
|
|
if let Some(inset) = &self.inset {
|
|
if inset.is_negative() {
|
|
ret.push(format!("-inset-[{inset}px]"));
|
|
} else {
|
|
ret.push(format!("inset-[{inset}px]"));
|
|
}
|
|
}
|
|
|
|
if let Some(inset) = &self.inset_x {
|
|
if inset.is_negative() {
|
|
ret.push(format!("-inset-x-[{inset}px]"));
|
|
} else {
|
|
ret.push(format!("inset-x-[{inset}px]"));
|
|
}
|
|
}
|
|
|
|
if let Some(inset) = &self.inset_y {
|
|
if inset.is_negative() {
|
|
ret.push(format!("-inset-y-[{inset}px]"));
|
|
} else {
|
|
ret.push(format!("inset-y-[{inset}px]"));
|
|
}
|
|
}
|
|
|
|
if let Some(start) = &self.start {
|
|
if start.is_negative() {
|
|
ret.push(format!("-start-[{start}px]"));
|
|
} else {
|
|
ret.push(format!("start-[{start}px]"));
|
|
}
|
|
}
|
|
|
|
if let Some(end) = &self.end {
|
|
if end.is_negative() {
|
|
ret.push(format!("-end-[{end}px]"));
|
|
} else {
|
|
ret.push(format!("end-[{end}px]"));
|
|
}
|
|
}
|
|
|
|
if let Some(value) = &self.top {
|
|
if value.is_negative() {
|
|
ret.push(format!("-top-[{value}px]"));
|
|
} else {
|
|
ret.push(format!("top-[{value}px]"));
|
|
}
|
|
}
|
|
|
|
if let Some(value) = &self.right {
|
|
if value.is_negative() {
|
|
ret.push(format!("-right-[{value}px]"));
|
|
} else {
|
|
ret.push(format!("right-[{value}px]"));
|
|
}
|
|
}
|
|
|
|
if let Some(value) = &self.bottom {
|
|
if value.is_negative() {
|
|
ret.push(format!("-bottom-[{value}px]"));
|
|
} else {
|
|
ret.push(format!("bottom-[{value}px]"));
|
|
}
|
|
}
|
|
|
|
if let Some(value) = &self.left {
|
|
if value.is_negative() {
|
|
ret.push(format!("-left-[{value}px]"));
|
|
} else {
|
|
ret.push(format!("left-[{value}px]"));
|
|
}
|
|
}
|
|
|
|
ret
|
|
}
|
|
|
|
fn extended_class(&self) -> Vec<String> {
|
|
let mut c = self.base_class();
|
|
c.extend_from_slice(&self.inner.extended_class());
|
|
c
|
|
}
|
|
|
|
fn render_with_class(&self, class: &str) -> Markup {
|
|
if self.inner.as_ref().can_inherit() {
|
|
self.inner
|
|
.as_ref()
|
|
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
|
|
} else {
|
|
html! {
|
|
div class=(format!("{} {class}", self.base_class().join(" "))) {
|
|
(self.inner.as_ref())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum PositionKind {
|
|
Static,
|
|
Fixed,
|
|
Absolute,
|
|
Relative,
|
|
Sticky,
|
|
}
|
|
|
|
impl PositionKind {
|
|
pub const fn to_value(&self) -> &str {
|
|
match self {
|
|
PositionKind::Static => "static",
|
|
PositionKind::Fixed => "fixed",
|
|
PositionKind::Absolute => "absolute",
|
|
PositionKind::Relative => "relative",
|
|
PositionKind::Sticky => "sticky",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
pub fn ObjectPosition<T: UIWidget + 'static>(side: Side, inner: T) -> ObjectPositioned {
|
|
ObjectPositioned {
|
|
inner: Box::new(inner),
|
|
side,
|
|
}
|
|
}
|
|
|
|
pub struct ObjectPositioned {
|
|
inner: Box<dyn UIWidget>,
|
|
side: Side,
|
|
}
|
|
|
|
impl Render for ObjectPositioned {
|
|
fn render(&self) -> Markup {
|
|
self.render_with_class("")
|
|
}
|
|
}
|
|
|
|
impl UIWidget for ObjectPositioned {
|
|
fn can_inherit(&self) -> bool {
|
|
true
|
|
}
|
|
|
|
fn base_class(&self) -> Vec<String> {
|
|
vec![
|
|
match self.side {
|
|
Side::Start => "object-top",
|
|
Side::End => "object-bottom",
|
|
Side::Top => "object-top",
|
|
Side::Right => "object-right",
|
|
Side::Bottom => "object-bottom",
|
|
Side::Left => "object-left",
|
|
Side::StartStart => "object-left-top",
|
|
Side::StartEnd => "object-right-top",
|
|
Side::EndEnd => "object-right-bottom",
|
|
Side::EndStart => "object-left-bottom",
|
|
Side::TopLeft => "object-left-top",
|
|
Side::TopRight => "object-right-top",
|
|
Side::BottomRight => "object-right-bottom",
|
|
Side::BottomLeft => "object-left-bottom",
|
|
Side::Center => "object-center",
|
|
}
|
|
.to_string(),
|
|
]
|
|
}
|
|
|
|
fn extended_class(&self) -> Vec<String> {
|
|
let mut c = self.base_class();
|
|
c.extend_from_slice(&self.inner.extended_class());
|
|
c
|
|
}
|
|
|
|
fn render_with_class(&self, class: &str) -> Markup {
|
|
if self.inner.as_ref().can_inherit() {
|
|
self.inner
|
|
.as_ref()
|
|
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
|
|
} else {
|
|
html! {
|
|
div class=(format!("{} {class}", self.base_class().join(" "))) {
|
|
(self.inner.as_ref())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum Resize {
|
|
None,
|
|
Y,
|
|
X,
|
|
Both,
|
|
}
|
|
|
|
impl Resize {
|
|
pub const fn to_value(&self) -> &str {
|
|
match self {
|
|
Resize::None => "resize-none",
|
|
Resize::Y => "resize-y",
|
|
Resize::X => "resize-x",
|
|
Resize::Both => "resize",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
pub fn Resizeable<T: UIWidget + 'static>(mode: Resize, inner: T) -> ResizeableWidget {
|
|
ResizeableWidget(Box::new(inner), mode)
|
|
}
|
|
|
|
pub struct ResizeableWidget(Box<dyn UIWidget>, Resize);
|
|
|
|
impl Render for ResizeableWidget {
|
|
fn render(&self) -> Markup {
|
|
self.render_with_class("")
|
|
}
|
|
}
|
|
|
|
impl UIWidget for ResizeableWidget {
|
|
fn can_inherit(&self) -> bool {
|
|
false
|
|
}
|
|
|
|
fn base_class(&self) -> Vec<String> {
|
|
vec![self.1.to_value().to_string()]
|
|
}
|
|
|
|
fn extended_class(&self) -> Vec<String> {
|
|
let mut c = self.base_class();
|
|
c.extend_from_slice(&self.0.extended_class());
|
|
c
|
|
}
|
|
|
|
fn render_with_class(&self, class: &str) -> Markup {
|
|
if self.0.as_ref().can_inherit() {
|
|
self.0
|
|
.as_ref()
|
|
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
|
|
} else {
|
|
html! {
|
|
div class=(format!("{} {class}", self.base_class().join(" "))) {
|
|
(self.0.as_ref())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|