1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! `NcScale`

/// Indicates how to scale an [`NcVisual`][crate::NcVisual] during rendering.
///
/// # Default
/// *[`NcScale::None`]*
///
/// # Application
/// The scaling preferences are applied only for the context of
/// [`NcVisual.render`][crate::NcVisual#method.render].
///
/// You can think of it as the following pipeline, where you still have
/// the original frame:
/// ```txt
/// NcVisual::from_file() → frame → NcVisual.render() → scaling → output_frame → blit
/// ```
///
/// Whereas
/// [`NcVisual.resize`][crate::NcVisual#method.resize] and
/// [`NcVisual.resize_noninterpolative`][crate::NcVisual#method.resize_noninterpolative]
/// are changing that original frame.
///
#[repr(u32)]
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum NcScale {
    /// Maintains the original size. Will Apply no scaling.
    None = c_api::NCSCALE_NONE,

    /// Maintains the aspect ratio.
    ///
    /// Scales an `NcVisual` to the `NcPlane`'s size without stretching.
    Scale = c_api::NCSCALE_SCALE,

    /// Like `None`, maintains the original size, while admitting
    /// high-resolution blitters that don't preserve the aspect ratio.
    NoneHiRes = c_api::NCSCALE_NONE_HIRES,

    /// Like `Scale`, maintains the aspect ratio, while admitting
    /// high-resolution blitters that don't preserve the aspect ratio.
    ScaleHiRes = c_api::NCSCALE_SCALE_HIRES,

    /// Throws away aspect ratio.
    ///
    /// Stretches and scales the `NcVisual` in an attempt to fill the entirety
    /// of the `NcPlane`.
    Stretch = c_api::NCSCALE_STRETCH,
}

mod std_impls {
    use super::{c_api, NcScale};
    use core::fmt;

    impl Default for NcScale {
        fn default() -> Self {
            Self::None
        }
    }

    impl fmt::Display for NcScale {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            use NcScale::*;
            write!(
                f,
                "{}",
                match self {
                    None => "None",
                    Scale => "Scale",
                    NoneHiRes => "NoneHiRes",
                    ScaleHiRes => "ScaleHiRes",
                    Stretch => "Stretch",
                }
            )
        }
    }

    impl fmt::Debug for NcScale {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "NcScale {{ {} }}", self)
        }
    }

    impl From<c_api::NcScale_u32> for NcScale {
        fn from(scale: c_api::NcScale_u32) -> Self {
            use {c_api::*, NcScale::*};
            match scale {
                NCSCALE_NONE => None,
                NCSCALE_SCALE => Scale,
                NCSCALE_NONE_HIRES => NoneHiRes,
                NCSCALE_SCALE_HIRES => ScaleHiRes,
                NCSCALE_STRETCH => Stretch,
                _ => Self::default(),
            }
        }
    }

    impl From<NcScale> for c_api::NcScale_u32 {
        fn from(scale: NcScale) -> Self {
            use {c_api::*, NcScale::*};
            match scale {
                None => NCSCALE_NONE,
                Scale => NCSCALE_SCALE,
                NoneHiRes => NCSCALE_NONE_HIRES,
                ScaleHiRes => NCSCALE_SCALE_HIRES,
                Stretch => NCSCALE_STRETCH,
            }
        }
    }
}

pub(crate) mod c_api {
    use crate::c_api::ffi;

    /// Indicates how to scale an [`NcVisual`][crate::NcVisual] during rendering.
    ///
    /// It's recommended to use [`NcScale`][crate::NcScale] instead.
    ///
    /// # Associated `c_api` constants
    ///
    /// - [`NCSCALE_NONE`] will apply no scaling.
    /// - [`NCSCALE_SCALE`] scales a visual to the plane's size,
    ///   maintaining aspect ratio.
    /// - [`NCSCALE_STRETCH`] stretches and scales the image in an
    ///   attempt to fill the entirety of the plane.
    /// - [`NCSCALE_NONE_HIRES`] like `NONE` admitting high-res blitters.
    /// - [`NCSCALE_SCALE_HIRES`] like `CALE` admitting high-res blitters.
    ///
    /// The `NCSCALE_*` preferences are applied only for the context of
    /// [`NcVisual.render`][crate::NcVisual#method.render].
    /// You can think of it as a pipeline:
    ///
    /// ```txt
    /// NcVisual::fromfile() → frame → NcVisual.render() → scaling → output frame → blit
    /// ```
    ///
    /// where you still have the original frame. Whereas
    /// [`NcVisual.resize`][crate::NcVisual#method.resize] and
    /// [`NcVisual.resize_noninterpolative`][crate::NcVisual#method.resize_noninterpolative]
    /// are changing that original frame.
    pub type NcScale_u32 = ffi::ncscale_e;

    /// [`NcScale_u32`] mode that maintains the original size.
    pub const NCSCALE_NONE: NcScale_u32 = ffi::ncscale_e_NCSCALE_NONE;

    /// [`NcScale_u32`] mode that maintains the aspect ratio.
    pub const NCSCALE_SCALE: NcScale_u32 = ffi::ncscale_e_NCSCALE_SCALE;

    /// [`NcScale_u32`] mode that throws away the aspect ratio.
    pub const NCSCALE_STRETCH: NcScale_u32 = ffi::ncscale_e_NCSCALE_STRETCH;

    /// [`NcScale_u32`] mode that maintains the original size, admitting
    /// high-resolution blitters that don't preserve the aspect ratio.
    pub const NCSCALE_NONE_HIRES: NcScale_u32 = ffi::ncscale_e_NCSCALE_NONE_HIRES;

    /// [`NcScale_u32`] mode that maintains the aspect ratio, admitting
    /// high-resolution blitters that don't preserve the aspect ratio.
    pub const NCSCALE_SCALE_HIRES: NcScale_u32 = ffi::ncscale_e_NCSCALE_SCALE_HIRES;
}