Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ rand_distr = "0.5.1"
rand_chacha = "0.9.0"
rfd = "0.17.1"
rustybuzz = "0.20.1"
serde = "1.0.228"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
strict-num = "0.2.0"
tiny-skia = "0.11.4"
Expand Down
46 changes: 0 additions & 46 deletions base/src/sd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,6 @@ where
) {
(true, true, true, true) => "auto".serialize(serializer),
(false, true, true, true) => stroke.color.serialize(serializer),
(true, false, true, true) => stroke.width.serialize(serializer),
(true, true, false, true) => stroke.pattern.serialize(serializer),
_ => {
let fields = (!has_default_color as usize)
Expand Down Expand Up @@ -681,13 +680,6 @@ impl<C> StrokeVisitor<C> {
)
}

fn no_default_numeric_message(&self) -> String {
format!(
"Numeric value is not valid for {} because there is no default stroke defined",
self.name
)
}

fn no_default_dash_array_message(&self) -> String {
format!(
"Dash array is not valid for {} because there is no default stroke defined",
Expand All @@ -712,44 +704,6 @@ where
formatter.write_str(self.expecting_description())
}

fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_f64(value as f64)
}

fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_f64(value as f64)
}

fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let Some(default) = self.default_stroke else {
return Err(serde::de::Error::custom(self.no_default_numeric_message()));
};

if value <= 0.0 {
return Err(serde::de::Error::custom(format!(
"Invalid stroke width for {}: width cannot be null or negative",
self.name
)));
}

let width = value as f32;
Ok(Stroke {
color: default.color,
width,
pattern: default.pattern,
opacity: default.opacity,
})
}

fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
Expand Down
10 changes: 6 additions & 4 deletions iced/examples/audio_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,8 +399,9 @@ fn build_figure() -> des::Figure {
.with_title("Frequency (Hz)".to_string().into())
.with_scale(des::axis::Range(Some(0.0), Some(4000.0)).into())
.with_ticks(
des::axis::Ticks::new()
.with_formatter(des::axis::ticks::Formatter::Prec(0).into()),
des::axis::Ticks::new().with_formatter(
des::axis::ticks::Formatter::Decimal(0.into()).into(),
),
)
.with_grid(Default::default()),
)
Expand All @@ -409,8 +410,9 @@ fn build_figure() -> des::Figure {
.with_title("Amplitude (dBFS)".to_string().into())
.with_scale(des::axis::Range(Some(-100.0), Some(0.0)).into())
.with_ticks(
des::axis::Ticks::new()
.with_formatter(des::axis::ticks::Formatter::Prec(0).into()),
des::axis::Ticks::new().with_formatter(
des::axis::ticks::Formatter::Decimal(0.into()).into(),
),
)
.with_grid(Default::default()),
),
Expand Down
14 changes: 7 additions & 7 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,13 @@ pub trait Column: std::fmt::Debug {
///
/// Panics if none of the f64, i64, str, time or time_delta methods return Some.
fn boxed_copy(&self) -> Box<dyn Column> {
#[cfg(feature = "time")]
if let Some(col) = self.time() {
return Box::new(col.time_iter().collect::<Vec<_>>());
} else if let Some(col) = self.time_delta() {
return Box::new(col.time_delta_iter().collect::<Vec<_>>());
}

if let Some(col) = self.f64() {
let mut vec = Vec::with_capacity(col.len());
for v in col.f64_iter() {
Expand All @@ -407,13 +414,6 @@ pub trait Column: std::fmt::Debug {
);
}

#[cfg(feature = "time")]
if let Some(col) = self.time() {
return Box::new(col.time_iter().collect::<Vec<_>>());
} else if let Some(col) = self.time_delta() {
return Box::new(col.time_delta_iter().collect::<Vec<_>>());
}

panic!("Cannot box copy column: no known type");
}

Expand Down
22 changes: 14 additions & 8 deletions src/des.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ pub use series::{DataCol, Series, data_inline, data_src_ref};
use crate::style::theme;
use crate::text;

/// Rich-Text properties for titles, labels, legends, etc.
pub type TextProps = text::TextProps<theme::Color>;

/// Text content for titles, labels, legends, etc.
#[derive(Debug, Clone, PartialEq)]
pub enum Text {
Expand All @@ -34,12 +37,12 @@ pub enum Text {
/// Rich text, the format string is parsed to produce a rich text, using the standard classes
Rich(String),
/// Rich text, the format string is parsed to produce a rich text,
/// and the non-standard classes can be used to define the properties of the spans
RichWithClasses {
/// The format string for the rich text, with optional classes
/// and the user defined props can be used to define the properties of the spans
RichWithProps {
/// The format string for the rich text, with optional properties classes
fmt: String,
/// The classes that can be used in the format string
classes: Vec<(String, text::TextProps<theme::Color>)>,
/// The properties that can be used in the format string
props: Vec<(String, TextProps)>,
},
}

Expand All @@ -60,7 +63,10 @@ impl Text {
let builder = parsed_text.into_builder(base).with_layout(layout);
builder.done(db)
}
Text::RichWithClasses { fmt, classes } => {
Text::RichWithProps {
fmt,
props: classes,
} => {
let parsed_text = text::parse_rich_text_with_classes(fmt, &classes)?;
let builder = parsed_text.into_builder(base).with_layout(layout);
builder.done(db)
Expand Down Expand Up @@ -147,9 +153,9 @@ impl From<(&str, &str, &str)> for Text {

impl From<(String, Vec<(String, text::TextProps<theme::Color>)>)> for Text {
fn from(tuple: (String, Vec<(String, text::TextProps<theme::Color>)>)) -> Self {
Text::RichWithClasses {
Text::RichWithProps {
fmt: tuple.0,
classes: tuple.1,
props: tuple.1,
}
}
}
Expand Down
34 changes: 32 additions & 2 deletions src/des/axis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ pub mod ticks {
/// Same as [Formatter::Auto] for all axes, even those that are shared.
SharedAuto,
/// Format the ticks with decimal precision
Prec(usize),
Decimal(DecimalFormatter),
/// The labels are percentages (E.g. `0.5` will be formatted as `50%`)
Percent(PercentFormatter),
#[cfg(feature = "time")]
Expand All @@ -586,7 +586,29 @@ pub mod ticks {
TimeDelta(TimeDeltaFormatter),
}

/// A label formatter for DateTime ticks
/// A label formatter that formats the ticks with a specified number of decimal places
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct DecimalFormatter {
/// Number of decimal places
/// None means automatic
pub decimal_places: Option<usize>,
}

impl From<DecimalFormatter> for Formatter {
fn from(fmt: DecimalFormatter) -> Self {
Formatter::Decimal(fmt)
}
}

impl From<usize> for DecimalFormatter {
fn from(digits: usize) -> Self {
DecimalFormatter {
decimal_places: Some(digits),
}
}
}

/// A label formatter that convert values to percentage and formats with provided decimal places
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct PercentFormatter {
/// Number of decimal places
Expand All @@ -600,6 +622,14 @@ pub mod ticks {
}
}

impl From<usize> for PercentFormatter {
fn from(digits: usize) -> Self {
PercentFormatter {
decimal_places: Some(digits),
}
}
}

#[cfg(feature = "time")]
/// A label formatter for DateTime ticks
#[derive(Debug, Clone, Default, PartialEq)]
Expand Down
Loading
Loading