Skip to main content

vb6parse/language/controls/
checkbox.rs

1//! Defines the properties and value enumeration for a `CheckBox` control in a VB6 form.
2//! This includes the `CheckBoxProperties` struct which holds all configurable
3//! properties of the `CheckBox`, as well as the `CheckBoxValue` enum which
4//! represents the state of the `CheckBox` (Unchecked, Checked, Grayed).
5//! These are used in the context of parsing and representing VB6 form controls.
6//!
7//! The properties covered include appearance, colors, captions, data binding,
8//! validation behavior, images, dimensions, and other control-specific settings.
9//!
10//! This struct is intended to be used as part of a larger control framework,
11//! specifically as a variant of the `ControlKind::CheckBox` enum.
12//!
13//! See [`ControlKind::CheckBox`](crate::language::controls::ControlKind::CheckBox)
14//! for usage.
15//!
16//! # References
17//! - [VB6 CheckBox Control Documentation](https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-basic-6/aa240800(v=vs.60))
18
19use std::fmt::Display;
20use std::str::FromStr;
21
22use crate::{
23    ErrorKind,
24    errors::FormError,
25    files::common::Properties,
26    language::{
27        Color, VB_BUTTON_FACE, VB_BUTTON_TEXT,
28        controls::{
29            Activation, Appearance, CausesValidation, DragMode, Font, JustifyAlignment,
30            MousePointer, OLEDropMode, ReferenceOrValue, Style, TabStop, TextDirection,
31            UseMaskColor, Visibility,
32        },
33    },
34};
35
36use image::DynamicImage;
37use num_enum::TryFromPrimitive;
38use serde::Serialize;
39
40/// Represents the current state of a checkbox control.
41///
42/// This is used as a property of the [`CheckBoxProperties`](crate::language::controls::CheckBoxProperties)
43/// struct.
44#[derive(
45    Debug, PartialEq, Eq, Clone, Serialize, TryFromPrimitive, Default, Copy, Hash, PartialOrd, Ord,
46)]
47#[repr(i32)]
48pub enum CheckBoxValue {
49    /// The checkbox is unchecked.
50    ///
51    /// This is the default value.
52    #[default]
53    Unchecked = 0,
54    /// The checkbox is checked.
55    Checked = 1,
56    /// The checkbox is grayed out and cannot be checked or unchecked.
57    Grayed = 2,
58}
59
60impl Display for CheckBoxValue {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        let text = match self {
63            CheckBoxValue::Unchecked => "Unchecked",
64            CheckBoxValue::Checked => "Checked",
65            CheckBoxValue::Grayed => "Grayed",
66        };
67        write!(f, "{text}")
68    }
69}
70
71impl FromStr for CheckBoxValue {
72    type Err = ErrorKind;
73
74    fn from_str(s: &str) -> Result<Self, Self::Err> {
75        match s {
76            "0" | "Unchecked" => Ok(CheckBoxValue::Unchecked),
77            "1" | "Checked" => Ok(CheckBoxValue::Checked),
78            "2" | "Grayed" => Ok(CheckBoxValue::Grayed),
79            _ => Err(ErrorKind::Form(FormError::InvalidCheckBoxValue {
80                value: s.to_string(),
81            })),
82        }
83    }
84}
85
86impl TryFrom<&str> for CheckBoxValue {
87    type Error = ErrorKind;
88
89    fn try_from(value: &str) -> Result<Self, Self::Error> {
90        CheckBoxValue::from_str(value)
91    }
92}
93
94/// Properties for a `CheckBox` control.
95///
96/// This is used as an enum variant of
97/// [`ControlKind::CheckBox`](crate::language::controls::ControlKind::CheckBox).
98/// tag, name, and index are not included in this struct, but instead are part
99/// of the parent [`Control`](crate::language::controls::Control) struct.
100#[derive(Debug, PartialEq, Clone)]
101pub struct CheckBoxProperties {
102    /// Justify alignment of the checkbox caption.
103    pub alignment: JustifyAlignment,
104    /// Appearance of the checkbox control.
105    pub appearance: Appearance,
106    /// Background color of the checkbox control.
107    pub back_color: Color,
108    /// Caption text of the checkbox control.
109    pub caption: String,
110    /// Whether the checkbox control causes validation.
111    pub causes_validation: CausesValidation,
112    /// Data field associated with the checkbox control.
113    pub data_field: String,
114    /// Data format for the checkbox control.
115    pub data_format: String,
116    /// Data member associated with the checkbox control.
117    pub data_member: String,
118    /// Data source associated with the checkbox control.
119    pub data_source: String,
120    /// Picture displayed when the checkbox is disabled.
121    pub disabled_picture: Option<ReferenceOrValue<DynamicImage>>,
122    /// Picture displayed when the checkbox is pressed down.
123    pub down_picture: Option<ReferenceOrValue<DynamicImage>>,
124    /// Icon used during drag operations.
125    pub drag_icon: Option<ReferenceOrValue<DynamicImage>>,
126    /// Drag mode of the checkbox control.
127    pub drag_mode: DragMode,
128    /// Whether the checkbox control is enabled.
129    pub enabled: Activation,
130    /// The font style for the form.
131    pub font: Option<Font>,
132    /// Foreground color of the checkbox control.
133    pub fore_color: Color,
134    /// Height of the checkbox control.
135    pub height: i32,
136    /// Help context ID associated with the checkbox control.
137    pub help_context_id: i32,
138    /// Left position of the checkbox control.
139    pub left: i32,
140    /// Mask color used for transparency.
141    pub mask_color: Color,
142    /// Icon displayed when the mouse is over the checkbox control.
143    pub mouse_icon: Option<ReferenceOrValue<DynamicImage>>,
144    /// Mouse pointer style when hovering over the checkbox control.
145    pub mouse_pointer: MousePointer,
146    /// OLE drop mode of the checkbox control.
147    pub ole_drop_mode: OLEDropMode,
148    /// Picture displayed on the checkbox control.
149    pub picture: Option<ReferenceOrValue<DynamicImage>>,
150    /// Text direction of the checkbox control.
151    pub right_to_left: TextDirection,
152    /// Style of the checkbox control.
153    pub style: Style,
154    /// Tab index of the checkbox control.
155    pub tab_index: i32,
156    /// Whether the checkbox control is included in the tab order.
157    pub tab_stop: TabStop,
158    /// Tool tip text for the checkbox control.
159    pub tool_tip_text: String,
160    /// Top position of the checkbox control.
161    pub top: i32,
162    /// Whether to use the mask color for transparency.
163    pub use_mask_color: UseMaskColor,
164    /// Current value/state of the checkbox control.
165    pub value: CheckBoxValue,
166    /// Visibility of the checkbox control.
167    pub visible: Visibility,
168    /// "What's This?" help ID associated with the checkbox control.
169    pub whats_this_help_id: i32,
170    /// Width of the checkbox control.
171    pub width: i32,
172}
173
174impl Default for CheckBoxProperties {
175    fn default() -> Self {
176        CheckBoxProperties {
177            alignment: JustifyAlignment::LeftJustify,
178            appearance: Appearance::ThreeD,
179            back_color: VB_BUTTON_FACE,
180            caption: String::new(),
181            causes_validation: CausesValidation::Yes,
182            data_field: String::new(),
183            data_format: String::new(),
184            data_member: String::new(),
185            data_source: String::new(),
186            disabled_picture: None,
187            down_picture: None,
188            drag_icon: None,
189            drag_mode: DragMode::Manual,
190            enabled: Activation::Enabled,
191            font: Some(Font::default()),
192            fore_color: VB_BUTTON_TEXT,
193            height: 30,
194            help_context_id: 0,
195            left: 30,
196            mask_color: Color::new(0xC0, 0xC0, 0xC0),
197            mouse_icon: None,
198            mouse_pointer: MousePointer::Default,
199            ole_drop_mode: OLEDropMode::default(),
200            picture: None,
201            right_to_left: TextDirection::LeftToRight,
202            style: Style::Standard,
203            tab_index: 0,
204            tab_stop: TabStop::Included,
205            tool_tip_text: String::new(),
206            top: 30,
207            use_mask_color: UseMaskColor::DoNotUseMaskColor,
208            value: CheckBoxValue::Unchecked,
209            visible: Visibility::Visible,
210            whats_this_help_id: 0,
211            width: 100,
212        }
213    }
214}
215
216impl Serialize for CheckBoxProperties {
217    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
218    where
219        S: serde::ser::Serializer,
220    {
221        use serde::ser::SerializeStruct;
222
223        let mut state = serializer.serialize_struct("CheckBoxProperties", 29)?;
224        state.serialize_field("alignment", &self.alignment)?;
225        state.serialize_field("appearance", &self.appearance)?;
226        state.serialize_field("back_color", &self.back_color)?;
227        state.serialize_field("caption", &self.caption)?;
228        state.serialize_field("causes_validation", &self.causes_validation)?;
229        state.serialize_field("data_field", &self.data_field)?;
230        state.serialize_field("data_format", &self.data_format)?;
231        state.serialize_field("data_member", &self.data_member)?;
232        state.serialize_field("data_source", &self.data_source)?;
233
234        let option_text = self.disabled_picture.as_ref().map(|_| "Some(DynamicImage)");
235
236        state.serialize_field("disabled_picture", &option_text)?;
237
238        let option_text = self.down_picture.as_ref().map(|_| "Some(DynamicImage)");
239
240        state.serialize_field("down_picture", &option_text)?;
241
242        let option_text = self.drag_icon.as_ref().map(|_| "Some(DynamicImage)");
243
244        state.serialize_field("drag_icon", &option_text)?;
245        state.serialize_field("drag_mode", &self.drag_mode)?;
246        state.serialize_field("enabled", &self.enabled)?;
247        state.serialize_field("fore_color", &self.fore_color)?;
248        state.serialize_field("height", &self.height)?;
249        state.serialize_field("help_context_id", &self.help_context_id)?;
250        state.serialize_field("left", &self.left)?;
251        state.serialize_field("mask_color", &self.mask_color)?;
252
253        let option_text = self.mouse_icon.as_ref().map(|_| "Some(DynamicImage)");
254
255        state.serialize_field("mouse_icon", &option_text)?;
256        state.serialize_field("mouse_pointer", &self.mouse_pointer)?;
257        state.serialize_field("ole_drop_mode", &self.ole_drop_mode)?;
258
259        let option_text = self.picture.as_ref().map(|_| "Some(DynamicImage)");
260
261        state.serialize_field("picture", &option_text)?;
262        state.serialize_field("right_to_left", &self.right_to_left)?;
263        state.serialize_field("style", &self.style)?;
264        state.serialize_field("tab_index", &self.tab_index)?;
265        state.serialize_field("tab_stop", &self.tab_stop)?;
266        state.serialize_field("tool_tip_text", &self.tool_tip_text)?;
267        state.serialize_field("top", &self.top)?;
268        state.serialize_field("use_mask_color", &self.use_mask_color)?;
269        state.serialize_field("value", &self.value)?;
270        state.serialize_field("visible", &self.visible)?;
271        state.serialize_field("whats_this_help_id", &self.whats_this_help_id)?;
272        state.serialize_field("width", &self.width)?;
273
274        state.end()
275    }
276}
277
278impl From<Properties> for CheckBoxProperties {
279    fn from(prop: Properties) -> Self {
280        let mut checkbox_prop = CheckBoxProperties::default();
281
282        checkbox_prop.alignment = prop.get_property("Alignment", checkbox_prop.alignment);
283        checkbox_prop.appearance = prop.get_property("Appearance", checkbox_prop.appearance);
284        checkbox_prop.back_color = prop.get_color("BackColor", checkbox_prop.back_color);
285        checkbox_prop.caption = match prop.get("Caption") {
286            Some(caption) => caption.into(),
287            None => checkbox_prop.caption,
288        };
289        checkbox_prop.causes_validation =
290            prop.get_property("CausesValidation", checkbox_prop.causes_validation);
291        checkbox_prop.data_field = match prop.get("DataField") {
292            Some(data_field) => data_field.into(),
293            None => checkbox_prop.data_field,
294        };
295        checkbox_prop.data_format = match prop.get("DataFormat") {
296            Some(data_format) => data_format.into(),
297            None => checkbox_prop.data_format,
298        };
299        checkbox_prop.data_member = match prop.get("DataMember") {
300            Some(data_member) => data_member.into(),
301            None => checkbox_prop.data_member,
302        };
303        checkbox_prop.data_source = match prop.get("DataSource") {
304            Some(data_source) => data_source.into(),
305            None => checkbox_prop.data_source,
306        };
307        //DisabledPicture
308        //DownPicture
309        //DragIcon
310
311        checkbox_prop.drag_mode = prop.get_property("DragMode", checkbox_prop.drag_mode);
312        checkbox_prop.enabled = prop.get_property("Enabled", checkbox_prop.enabled);
313        checkbox_prop.fore_color = prop.get_color("ForeColor", checkbox_prop.fore_color);
314        checkbox_prop.height = prop.get_i32("Height", checkbox_prop.height);
315        checkbox_prop.help_context_id =
316            prop.get_i32("HelpContextID", checkbox_prop.help_context_id);
317        checkbox_prop.left = prop.get_i32("Left", checkbox_prop.left);
318        checkbox_prop.mask_color = prop.get_color("MaskColor", checkbox_prop.mask_color);
319
320        //MouseIcon
321
322        checkbox_prop.mouse_pointer =
323            prop.get_property("MousePointer", checkbox_prop.mouse_pointer);
324        checkbox_prop.ole_drop_mode = prop.get_property("OLEDropMode", checkbox_prop.ole_drop_mode);
325
326        //Picture
327
328        checkbox_prop.right_to_left = prop.get_property("RightToLeft", checkbox_prop.right_to_left);
329        checkbox_prop.style = prop.get_property("Style", checkbox_prop.style);
330        checkbox_prop.tab_index = prop.get_i32("TabIndex", checkbox_prop.tab_index);
331        checkbox_prop.tab_stop = prop.get_property("TabStop", checkbox_prop.tab_stop);
332        checkbox_prop.tool_tip_text = match prop.get("ToolTipText") {
333            Some(tool_tip_text) => tool_tip_text.into(),
334            None => checkbox_prop.tool_tip_text,
335        };
336        checkbox_prop.top = prop.get_i32("Top", checkbox_prop.top);
337        checkbox_prop.use_mask_color =
338            prop.get_property("UseMaskColor", checkbox_prop.use_mask_color);
339        checkbox_prop.value = prop.get_property("Value", checkbox_prop.value);
340        checkbox_prop.visible = prop.get_property("Visible", checkbox_prop.visible);
341        checkbox_prop.whats_this_help_id =
342            prop.get_i32("WhatsThisHelp", checkbox_prop.whats_this_help_id);
343        checkbox_prop.width = prop.get_i32("Width", checkbox_prop.width);
344
345        checkbox_prop
346    }
347}