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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! ## 2.4 Property Types
//!
//! Specifies data types that are used by more than one control.

#[allow(unused_imports)]
use num_traits::{FromPrimitive, ToPrimitive};

pub mod color;
pub mod font;
mod parser;
pub use parser::*;

use crate::controls::user_form::class_table::SiteClassInfo;
pub mod picture;
pub mod string;

/// An unsigned integer that specifies the type of icon displayed as the mouse pointer for the control.
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum MousePointer {
    /// Standard pointer.
    Default = 0x00,
    /// Arrow.
    Arrow = 0x01,
    /// Cross-hair pointer.
    Cross = 0x02,
    /// I-beam.
    IBeam = 0x03,
    /// Double arrow pointing northeast and southwest.
    SizeNESW = 0x06,
    /// Double arrow pointing north and south.
    SizeNS = 0x07,
    /// Double arrow pointing northwest and southeast.
    SizeNWSE = 0x08,
    /// Double arrow pointing west and east.
    SizeWE = 0x09,
    /// Up arrow.
    UpArrow = 0x0A,
    /// Hourglass.
    HourGlass = 0x0B,
    /// "Not" symbol (circle with a diagonal line) on top of the object being dragged.
    NoDrop = 0x0C,
    /// Arrow with an hourglass.
    AppStarting = 0x0D,
    /// Arrow with a question mark.
    Help = 0x0E,
    /// "Size-all" cursor (arrows pointing north, south, east, and west).
    SizeAll = 0x0F,
    /// Uses the icon specified by the MouseIcon property.
    Custom = 0x63,
}

/// Specifies the visual appearance of the control.
///
/// In this enumeration, "form" refers to the surface on which the control appears.
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum SpecialEffect {
    /// Control appears flat.
    Flat = 0x00,
    /// Control appears to be raised up from the form.
    Raised = 0x01,
    /// Control appears to be carved into the form.
    Sunken = 0x02,
    /// The control border appears to be carved into the form.
    Etched = 0x03,
    /// The control border appears to be raised up from the form.
    Bump = 0x06,
}

/// Specifies the alignment of the picture in the Form or Image.
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum PictureAlignment {
    /// The top-left corner.
    TopLeft = 0x00,
    /// The top-right corner.
    TopRight = 0x01,
    /// The center.
    Center = 0x02,
    /// The bottom-left corner.
    BottomLeft = 0x03,
    /// The bottom-right corner.
    BottomRight = 0x04,
}

/// Specifies how to display the picture.
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum PictureSizeMode {
    /// Crops any part of the picture that is larger than the control boundaries.
    Clip = 0x00,
    /// Stretches the picture to fill the control area. This setting distorts the picture in either the horizontal or vertical direction.
    Stretch = 0x01,
    /// Enlarges the picture, but does not distort the picture in either the horizontal or vertical direction.
    Zoom = 0x03,
}

pub type HiMetric = u32;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[doc(alias = "fmSize")]
/// Specifies a pair of signed integers that specify the size of a control.
pub struct Size {
    /// A signed integer that specifies the width, in HIMETRIC units, of the control.
    pub width: HiMetric,
    /// A signed integer that specifies the height, in HIMETRIC units, of the control.
    pub height: HiMetric,
}

impl Size {
    pub const fn new(width: HiMetric, height: HiMetric) -> Self {
        Self { width, height }
    }
}

pub type SignedHiMetric = i32;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
#[doc(alias = "fmPosition")]
/// Specifies a pair of signed integers that specify a position relative to a reference point.
///
/// Definition: [2.4.1 fmPosition](https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-oforms/73c3866f-bbac-4f45-ba70-645fd046bfdf)
///
/// **Note**: The MS-OFORMS spec has the field order reversed for all versions up to and including
/// 7.0. To quote from the relevant Q&A:
///
/// > The fmPosition struct matches the Windows API [`POINT`] structure (x then y)  
/// > &mdash; <https://learn.microsoft.com/en-us/answers/questions/1414725/are-the-fields-in-ms-oforms-in-fmposition-swapped>
///
/// [`POINT`]: https://learn.microsoft.com/en-us/windows/win32/api/windef/ns-windef-point
pub struct Position {
    /// A signed integer that specifies, in HIMETRIC units, a distance to the right of the reference point.
    pub left: SignedHiMetric,
    /// A signed integer that specifies, in HIMETRIC units, a distance below the reference point.
    pub top: SignedHiMetric,
}

impl Position {
    pub fn new(left: SignedHiMetric, top: SignedHiMetric) -> Self {
        Self { left, top }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum FormEmbeddedActiveXControlCached {
    Form = 7,
    Image = 12,
    Frame = 14,
    MorphData = 15,
    SpinButton = 16,
    CommandButton = 17,
    TabStrip = 18,
    Label = 21,
    TextBox = 23,
    ListBox = 24,
    ComboBox = 25,
    CheckBox = 26,
    OptionButton = 27,
    ToggleButton = 28,
    ScrollBar = 47,
    MultiPage = 57,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum FormEmbeddedActiveXControl<'a> {
    ControlCached(FormEmbeddedActiveXControlCached),
    ControlNonCached(&'a SiteClassInfo),
}

#[cfg(test)]
mod tests {
    use crate::properties::{HiMetric, SignedHiMetric, Size};

    use super::Position;

    #[test]
    fn test_position() {
        assert_eq!(
            Position::parse::<nom::error::Error<_>>(&[10, 0, 0, 0, 5, 0, 0, 0]),
            Ok((&[][..], Position { left: 10, top: 5 }))
        );
    }

    #[test]
    fn test_struct_alignment() {
        assert_eq!(std::mem::align_of::<Position>(), 4);
        assert_eq!(std::mem::align_of::<Size>(), 4);
        assert_eq!(std::mem::align_of::<HiMetric>(), 4);
        assert_eq!(std::mem::align_of::<SignedHiMetric>(), 4);
    }

    #[test]
    fn test_struct_size() {
        assert_eq!(std::mem::size_of::<Position>(), 8);
        assert_eq!(std::mem::size_of::<Size>(), 8);
        assert_eq!(std::mem::size_of::<HiMetric>(), 4);
        assert_eq!(std::mem::size_of::<SignedHiMetric>(), 4);
    }
}