Skip to content

Commit 5c277e4

Browse files
committed
Implement Resolvable for Rgb, gradients and GradientView
1 parent f387cec commit 5c277e4

File tree

7 files changed

+371
-54
lines changed

7 files changed

+371
-54
lines changed

cursive-core/src/builder.rs

+5
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ where
108108
}
109109

110110
impl<T> ResolveOnce<T> {
111+
/// Create a new `ResolveOnce` which will resolve, once, to the given value.
112+
pub fn new(value: T) -> Self {
113+
Self(std::sync::Arc::new(std::sync::Mutex::new(Some(value))))
114+
}
115+
111116
/// Take the value from self.
112117
pub fn take(&self) -> Option<T> {
113118
self.0.lock().unwrap().take()

cursive-core/src/builder/resolvable.rs

+205
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,172 @@ impl Resolvable for crate::style::Rgb<u8> {
474474
}
475475
}
476476

477+
impl Resolvable for crate::style::gradient::Dynterpolator {
478+
fn from_config(config: &Config, context: &Context) -> Result<Self, Error>
479+
where
480+
Self: Sized,
481+
{
482+
let config = config
483+
.as_object()
484+
.ok_or_else(|| Error::invalid_config("Expected object", config))?;
485+
match config
486+
.iter()
487+
.next()
488+
.map(|(key, config)| (key.as_str(), config))
489+
.ok_or_else(|| Error::invalid_config("Expected non-empty object", config))?
490+
{
491+
("radial", config) => {
492+
let radial: crate::style::gradient::Radial = context.resolve(config)?;
493+
Ok(Box::new(radial))
494+
}
495+
("angled", config) => {
496+
let angled: crate::style::gradient::Angled = context.resolve(config)?;
497+
Ok(Box::new(angled))
498+
}
499+
("bilinear", config) => {
500+
let bilinear: crate::style::gradient::Bilinear = context.resolve(config)?;
501+
Ok(Box::new(bilinear))
502+
}
503+
// TODO: Allow external libraries to define their own recipes to be used here?
504+
// Something like a type-map of recipes?...
505+
(key, _) => Err(Error::invalid_config(
506+
format!("Received unsupported gradient type {key}."),
507+
config,
508+
)),
509+
}
510+
}
511+
}
512+
513+
impl Resolvable for crate::style::gradient::Bilinear {
514+
fn from_config(config: &Config, context: &Context) -> Result<Self, Error>
515+
where
516+
Self: Sized,
517+
{
518+
let top_left = context.resolve(&config["top_left"])?;
519+
let top_right = context.resolve(&config["top_right"])?;
520+
let bottom_right = context.resolve(&config["bottom_right"])?;
521+
let bottom_left = context.resolve(&config["bottom_left"])?;
522+
Ok(Self {
523+
top_left,
524+
top_right,
525+
bottom_right,
526+
bottom_left,
527+
})
528+
}
529+
}
530+
531+
impl Resolvable for crate::style::gradient::Angled {
532+
fn from_config(config: &Config, context: &Context) -> Result<Self, Error>
533+
where
534+
Self: Sized,
535+
{
536+
let angle_rad = match context.resolve(&config["angle_rad"]) {
537+
Ok(angle_rad) => angle_rad,
538+
Err(err1) => match context.resolve::<f32>(&config["angle_deg"]) {
539+
Ok(angle_deg) => angle_deg * std::f32::consts::PI / 180f32,
540+
Err(err2) => {
541+
return Err(Error::AllVariantsFailed {
542+
config: config.clone(),
543+
errors: vec![err1, err2],
544+
})
545+
}
546+
},
547+
};
548+
let gradient = context.resolve(&config["gradient"])?;
549+
Ok(Self {
550+
angle_rad,
551+
gradient,
552+
})
553+
}
554+
}
555+
556+
impl Resolvable for crate::style::gradient::Radial {
557+
fn from_config(config: &Config, context: &Context) -> Result<Self, Error>
558+
where
559+
Self: Sized,
560+
{
561+
let center = context.resolve(&config["center"])?;
562+
let gradient = context.resolve(&config["gradient"])?;
563+
Ok(Self { center, gradient })
564+
}
565+
}
566+
567+
impl Resolvable for crate::style::gradient::Linear {
568+
fn from_config(config: &Config, context: &Context) -> Result<Self, Error>
569+
where
570+
Self: Sized,
571+
{
572+
use crate::style::Rgb;
573+
574+
// Options:
575+
// - A list of Rgb (evenly spaced)
576+
// - A list of (f32, Rgb)
577+
// - An object with start, end, and optionally middle, with a list of (f32, Rgb)
578+
// - Some presets strings? Rainbow?
579+
match config {
580+
Config::Array(array) => {
581+
let mut errors = Vec::new();
582+
583+
match array
584+
.iter()
585+
.map(|config| context.resolve::<Rgb<f32>>(config))
586+
.collect::<Result<Vec<_>, _>>()
587+
{
588+
Ok(colors) => return Ok(Self::evenly_spaced(&colors)),
589+
Err(err) => errors.push(err),
590+
}
591+
592+
match array
593+
.iter()
594+
.map(|config| context.resolve(config))
595+
.collect::<Result<Vec<_>, _>>()
596+
{
597+
Ok(points) => return Ok(Self::new(points)),
598+
Err(err) => errors.push(err),
599+
}
600+
601+
return Err(Error::AllVariantsFailed {
602+
config: config.clone(),
603+
errors,
604+
});
605+
}
606+
Config::Object(object) => {
607+
if let (Some(start), Some(end)) = (object.get("start"), object.get("end")) {
608+
return Ok(Self::simple(
609+
context.resolve::<Rgb<f32>>(start)?,
610+
context.resolve::<Rgb<f32>>(end)?,
611+
));
612+
}
613+
614+
if let Some(points) = object.get("points") {
615+
let points = points
616+
.as_array()
617+
.ok_or_else(|| Error::invalid_config("Expected array", config))?;
618+
619+
let points = points
620+
.iter()
621+
.map(|config| context.resolve(config))
622+
.collect::<Result<Vec<_>, _>>()?;
623+
624+
return Ok(Self::new(points));
625+
}
626+
}
627+
Config::String(string) => match string.as_str() {
628+
// TODO: Allow external libs to define their own aliases to resolve here?
629+
"rainbow" => return Ok(Self::rainbow()),
630+
"black_to_white" | "black to white" => return Ok(Self::black_to_white()),
631+
_ => (),
632+
},
633+
_ => (),
634+
}
635+
636+
Err(Error::invalid_config(
637+
"Expected array, object or string",
638+
config,
639+
))
640+
}
641+
}
642+
477643
// ```yaml
478644
// color: red
479645
// color:
@@ -602,6 +768,45 @@ impl Resolvable for String {
602768
}
603769
}
604770

771+
impl<A, B> Resolvable for (A, B)
772+
where
773+
A: Resolvable + 'static,
774+
B: Resolvable + 'static,
775+
{
776+
fn from_config(config: &Config, context: &Context) -> Result<Self, Error>
777+
where
778+
Self: Sized,
779+
{
780+
let config = config
781+
.as_array()
782+
.ok_or_else(|| Error::invalid_config("Expected array", config))?;
783+
784+
Ok((context.resolve(&config[0])?, context.resolve(&config[1])?))
785+
}
786+
}
787+
788+
impl<A, B, C> Resolvable for (A, B, C)
789+
where
790+
A: Resolvable + 'static,
791+
B: Resolvable + 'static,
792+
C: Resolvable + 'static,
793+
{
794+
fn from_config(config: &Config, context: &Context) -> Result<Self, Error>
795+
where
796+
Self: Sized,
797+
{
798+
let config = config
799+
.as_array()
800+
.ok_or_else(|| Error::invalid_config("Expected array", config))?;
801+
802+
Ok((
803+
context.resolve(&config[0])?,
804+
context.resolve(&config[1])?,
805+
context.resolve(&config[2])?,
806+
))
807+
}
808+
}
809+
605810
impl Resolvable for crate::utils::markup::StyledString {
606811
fn from_config(config: &Config, context: &Context) -> Result<Self, Error>
607812
where

cursive-core/src/style/color.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,21 @@ impl Rgb<u8> {
219219
Self::from_u32(0xFF0000)
220220
}
221221

222+
/// Returns an orange RGB color.
223+
pub const fn orange() -> Self {
224+
Self::from_u32(0xFFA500)
225+
}
226+
227+
/// Returns a violet RGB color.
228+
pub const fn violet() -> Self {
229+
Self::from_u32(0x7F00FF)
230+
}
231+
232+
/// Returns a turquoise color.
233+
pub const fn turquoise() -> Self {
234+
Self::from_u32(0x40E0D0)
235+
}
236+
222237
/// Returns a pure green RGB color.
223238
pub const fn green() -> Self {
224239
Self::from_u32(0x00FF00)
@@ -229,15 +244,15 @@ impl Rgb<u8> {
229244
Self::from_u32(0x0000FF)
230245
}
231246

232-
/// Returns a pure yellow RGB color.
247+
/// Returns a yellow (red + green) RGB color.
233248
pub const fn yellow() -> Self {
234249
Self::from_u32(0xFFFF00)
235250
}
236-
/// Returns a pure magenta RGB color.
251+
/// Returns a magenta (red + blue) RGB color.
237252
pub const fn magenta() -> Self {
238253
Self::from_u32(0xFF00FF)
239254
}
240-
/// Returns a pure cyan RGB color.
255+
/// Returns a cyan (green + blue) RGB color.
241256
pub const fn cyan() -> Self {
242257
Self::from_u32(0x00FFFF)
243258
}

0 commit comments

Comments
 (0)