summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/options.rs36
-rw-r--r--src/types/element_name.rs9
-rwxr-xr-xsrc/types/rendered_element.rs36
-rw-r--r--src/values.rs1
-rw-r--r--src/values/sizing.rs109
5 files changed, 186 insertions, 5 deletions
diff --git a/src/options.rs b/src/options.rs
index 2dc25d7..2ebdd5f 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -1,9 +1,10 @@
use std::collections::BTreeMap;
use std::str::FromStr;
+use iced::widget::grid::Sizing;
use iced::widget::text::LineHeight;
#[allow(unused_imports)]
-use iced::widget::{Button, Column, Container, Image, Row, Svg, Text};
+use iced::widget::{Button, Column, Container, Grid, Image, Row, Svg, Text};
use iced::{Alignment, ContentFit, Length, Padding, Pixels, Rotation};
use crate::values::Value;
@@ -258,6 +259,39 @@ impl<Message> ApplyOptions for Row<'_, Message> {
}
}
+impl<'a, Message> ApplyOptions for Grid<'a, Message> {
+ fn apply_options(self, options: BTreeMap<String, Option<String>>) -> Self {
+ let mut grid = self;
+
+ if let Some(spacing) = options.get("spacing").expect("spacing key") {
+ let spacing = f32::from_str(spacing).unwrap();
+ grid = grid.spacing(spacing);
+ }
+
+ if let Some(width) = options.get("width").expect("width key") {
+ let width = Pixels::from_str(width).unwrap();
+ grid = grid.width(width);
+ }
+
+ if let Some(height) = options.get("height").expect("height key") {
+ let height = Sizing::from_str(height).unwrap();
+ grid = grid.height(height);
+ }
+
+ if let Some(columns) = options.get("columns").expect("columns key") {
+ let columns = usize::from_str(columns).unwrap();
+ grid = grid.columns(columns);
+ }
+
+ if let Some(fluid) = options.get("fluid").expect("fluid key") {
+ let fluid = Pixels::from_str(fluid).unwrap();
+ grid = grid.fluid(fluid);
+ }
+
+ grid
+ }
+}
+
impl<Handle> ApplyOptions for Image<Handle> {
fn apply_options(self, options: BTreeMap<String, Option<String>>) -> Self {
let mut image = self;
diff --git a/src/types/element_name.rs b/src/types/element_name.rs
index c824fc5..8f8ab7e 100644
--- a/src/types/element_name.rs
+++ b/src/types/element_name.rs
@@ -1,7 +1,8 @@
use serde::{Deserialize, Serialize};
use super::rendered_element::{
- Action, RenderedElement, button, column, container, image, row, svg, text,
+ Action, RenderedElement, button, column, container, grid, image, row, svg,
+ text,
};
use crate::Error;
@@ -14,10 +15,11 @@ pub enum ElementName {
Container,
Row,
Column,
+ Grid,
}
impl ElementName {
- pub const ALL: &'static [Self; 7] = &[
+ pub const ALL: &'static [Self; 8] = &[
Self::Text(String::new()),
Self::Button(String::new()),
Self::Svg(String::new()),
@@ -25,6 +27,7 @@ impl ElementName {
Self::Container,
Self::Row,
Self::Column,
+ Self::Grid,
];
pub fn handle_action(
@@ -40,6 +43,7 @@ impl ElementName {
Self::Container => container(None),
Self::Row => row(vec![]),
Self::Column => column(vec![]),
+ Self::Grid => grid(vec![]),
};
match action {
Action::Stop | Action::Drop => Ok(None),
@@ -79,6 +83,7 @@ impl std::fmt::Display for ElementName {
Self::Container => "Container",
Self::Row => "Row",
Self::Column => "Column",
+ Self::Grid => "Grid",
}
)
}
diff --git a/src/types/rendered_element.rs b/src/types/rendered_element.rs
index 1ad7cdf..15e851c 100755
--- a/src/types/rendered_element.rs
+++ b/src/types/rendered_element.rs
@@ -1,9 +1,8 @@
use std::collections::BTreeMap;
-use iced::Element;
use iced::advanced::widget::Id;
use iced::widget::text::IntoFragment;
-use iced::widget::{self};
+use iced::{Element, widget};
use serde::{Deserialize, Serialize};
use crate::Error;
@@ -215,6 +214,12 @@ impl RenderedElement {
imports = format!("{imports}column,");
view = format!("{view}\ncolumn![{elements}]{options}");
}
+ ElementName::Grid => {
+ imports = format!("{imports}grid,");
+ view = format!(
+ "{view}\ngrid([{elements}].map(Into::into)){options}"
+ );
+ }
ElementName::Text(string) => {
imports = format!("{imports}text,");
view = format!(
@@ -389,6 +394,28 @@ impl<'a> From<RenderedElement> for Element<'a, Message> {
..Default::default()
})
.into(),
+ ElementName::Grid => widget::container(
+ if !child_elements.is_empty() {
+ widget::grid(child_elements.into_iter().map(Into::into))
+ } else {
+ widget::grid([text("New Column").into()])
+ }
+ .apply_options(copy.options),
+ )
+ .padding(20)
+ .style(|theme: &iced::Theme| widget::container::Style {
+ border: iced::Border {
+ color: theme.palette().warning.scale_alpha(0.6),
+
+ width: 2.0,
+ radius: 4.into(),
+ },
+ background: Some(
+ theme.palette().warning.scale_alpha(0.25).into(),
+ ),
+ ..Default::default()
+ })
+ .into(),
};
iced_drop::droppable(content)
@@ -546,3 +573,8 @@ pub fn column(child_elements: Vec<RenderedElement>) -> RenderedElement {
],
)
}
+
+pub fn grid(child_elements: Vec<RenderedElement>) -> RenderedElement {
+ RenderedElement::with(ElementName::Grid, child_elements)
+ .preset_options(&["spacing", "width", "height", "columns", "fluid"])
+}
diff --git a/src/values.rs b/src/values.rs
index d2dae74..62997ad 100644
--- a/src/values.rs
+++ b/src/values.rs
@@ -5,6 +5,7 @@ mod line_height;
mod padding;
mod pixels;
mod rotation;
+mod sizing;
pub trait Value: Sized {
type Err;
diff --git a/src/values/sizing.rs b/src/values/sizing.rs
new file mode 100644
index 0000000..e6a5086
--- /dev/null
+++ b/src/values/sizing.rs
@@ -0,0 +1,109 @@
+use std::num::ParseFloatError;
+use std::str::FromStr;
+
+use iced::Length;
+use iced::widget::grid::Sizing;
+
+use super::Value;
+use super::length::ParseLengthError;
+
+#[derive(Debug, thiserror::Error, Clone, PartialEq)]
+pub enum ParseSizingError {
+ #[error("float parsing error: {0}")]
+ ParseFloatError(ParseFloatError),
+ #[error("length parsing error: {0}")]
+ ParseLengthError(#[from] ParseLengthError),
+ #[error("invalid prefix")]
+ InvalidPrefix,
+ #[error("missing prefix")]
+ MissingPrefix,
+ #[error("cannot parse sizing from empty string")]
+ Empty,
+}
+
+impl From<ParseFloatError> for ParseSizingError {
+ fn from(value: ParseFloatError) -> Self {
+ Self::ParseFloatError(value)
+ }
+}
+
+impl Value for Sizing {
+ type Err = ParseSizingError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let s = s.trim();
+
+ if s.is_empty() {
+ return Err(ParseSizingError::Empty);
+ }
+
+ if s.starts_with(|c: char| c.is_ascii_digit()) {
+ return Err(ParseSizingError::MissingPrefix);
+ }
+
+ let (prefix, value) = s.split_at(2);
+ match prefix.to_lowercase().as_str() {
+ "ar" => Ok(Self::AspectRatio(f32::from_str(value)?)),
+ "ed" => Ok(Self::EvenlyDistribute(Length::from_str(value)?)),
+ _ => Err(ParseSizingError::InvalidPrefix),
+ }
+ }
+
+ fn to_string(&self) -> String {
+ match self {
+ Self::AspectRatio(ratio) => format!("ar{ratio}"),
+ Self::EvenlyDistribute(length) => {
+ format!("ed{}", length.to_string())
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn can_parse_ratio() {
+ assert_eq!(Sizing::from_str("ar5.1"), Ok(Sizing::AspectRatio(5.1)))
+ }
+
+ #[test]
+ fn can_parse_distribute_with_space() {
+ assert_eq!(
+ Sizing::from_str(" edfp2 "),
+ Ok(Sizing::EvenlyDistribute(Length::FillPortion(2)))
+ )
+ }
+
+ #[test]
+ fn cant_parse_invalid_prefix() {
+ assert_eq!(
+ Sizing::from_str("bc4.1 "),
+ Err(ParseSizingError::InvalidPrefix)
+ )
+ }
+
+ #[test]
+ fn cant_parse_invalid_float() {
+ assert_eq!(
+ Sizing::from_str(" ar2.a"),
+ Err(ParseSizingError::ParseFloatError(
+ f32::from_str("2.a").expect_err("float parse should fail")
+ ))
+ )
+ }
+
+ #[test]
+ fn cant_parse_with_missing_prefix() {
+ assert_eq!(
+ Sizing::from_str("2.4"),
+ Err(ParseSizingError::MissingPrefix)
+ )
+ }
+
+ #[test]
+ fn cant_parse_empty_string() {
+ assert_eq!(Sizing::from_str(" "), Err(ParseSizingError::Empty))
+ }
+}