use std::convert::TryFrom;
use std::fmt::Display;
use std::str::FromStr;
use crate::{
errors::{ErrorKind, FormError},
files::common::Properties,
language::{
controls::{
Activation, Appearance, AutoRedraw, ClipControls, DrawMode, DrawStyle, FillStyle,
FontTransparency, HasDeviceContext, MousePointer, Movability, OLEDropMode,
ReferenceOrValue, ScaleMode, StartUpPosition, TextDirection, Visibility, WhatsThisHelp,
WindowState,
},
Color, FormLinkMode, VB_BUTTON_FACE, VB_BUTTON_TEXT, VB_SCROLL_BARS,
},
};
use image::DynamicImage;
use num_enum::TryFromPrimitive;
use serde::Serialize;
#[derive(
Debug,
PartialEq,
Eq,
Clone,
serde::Serialize,
Default,
TryFromPrimitive,
Copy,
Hash,
PartialOrd,
Ord,
)]
#[repr(i32)]
pub enum PaletteMode {
#[default]
HalfTone = 0,
UseZOrder = 1,
Custom = 2,
}
impl TryFrom<&str> for PaletteMode {
type Error = crate::errors::ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"0" => Ok(PaletteMode::HalfTone),
"1" => Ok(PaletteMode::UseZOrder),
"2" => Ok(PaletteMode::Custom),
_ => Err(ErrorKind::Form(FormError::InvalidPaletteMode {
value: value.to_string(),
})),
}
}
}
impl FromStr for PaletteMode {
type Err = crate::errors::ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
PaletteMode::try_from(s)
}
}
impl Display for PaletteMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
PaletteMode::HalfTone => "HalfTone",
PaletteMode::UseZOrder => "UseZOrder",
PaletteMode::Custom => "Custom",
};
write!(f, "{text}")
}
}
#[derive(
Debug,
PartialEq,
Eq,
Clone,
Default,
TryFromPrimitive,
serde::Serialize,
Copy,
Hash,
PartialOrd,
Ord,
)]
#[repr(i32)]
pub enum FormBorderStyle {
None = 0,
FixedSingle = 1,
#[default]
Sizable = 2,
FixedDialog = 3,
FixedToolWindow = 4,
SizableToolWindow = 5,
}
impl TryFrom<&str> for FormBorderStyle {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"0" => Ok(FormBorderStyle::None),
"1" => Ok(FormBorderStyle::FixedSingle),
"2" => Ok(FormBorderStyle::Sizable),
"3" => Ok(FormBorderStyle::FixedDialog),
"4" => Ok(FormBorderStyle::FixedToolWindow),
"5" => Ok(FormBorderStyle::SizableToolWindow),
_ => Err(ErrorKind::Form(FormError::InvalidFormBorderStyle {
value: value.to_string(),
})),
}
}
}
impl FromStr for FormBorderStyle {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
FormBorderStyle::try_from(s)
}
}
impl Display for FormBorderStyle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
FormBorderStyle::None => "None",
FormBorderStyle::FixedSingle => "FixedSingle",
FormBorderStyle::Sizable => "Sizable",
FormBorderStyle::FixedDialog => "FixedDialog",
FormBorderStyle::FixedToolWindow => "FixedToolWindow",
FormBorderStyle::SizableToolWindow => "SizableToolWindow",
};
write!(f, "{text}")
}
}
#[derive(
Debug,
PartialEq,
Eq,
Clone,
Default,
TryFromPrimitive,
serde::Serialize,
Copy,
Hash,
PartialOrd,
Ord,
)]
#[repr(i32)]
pub enum ControlBox {
Excluded = 0,
#[default]
Included = -1,
}
impl TryFrom<&str> for ControlBox {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"0" => Ok(ControlBox::Excluded),
"-1" => Ok(ControlBox::Included),
_ => Err(ErrorKind::Form(FormError::InvalidControlBox {
value: value.to_string(),
})),
}
}
}
impl TryFrom<bool> for ControlBox {
type Error = ErrorKind;
fn try_from(value: bool) -> Result<Self, Self::Error> {
if value {
Ok(ControlBox::Included)
} else {
Ok(ControlBox::Excluded)
}
}
}
impl FromStr for ControlBox {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
ControlBox::try_from(s)
}
}
impl Display for ControlBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
ControlBox::Excluded => "Excluded",
ControlBox::Included => "Included",
};
write!(f, "{text}")
}
}
#[derive(
Debug,
PartialEq,
Eq,
Clone,
Default,
TryFromPrimitive,
serde::Serialize,
Copy,
Hash,
PartialOrd,
Ord,
)]
#[repr(i32)]
pub enum MaxButton {
Excluded = 0,
#[default]
Included = -1,
}
impl TryFrom<&str> for MaxButton {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"0" => Ok(MaxButton::Excluded),
"-1" => Ok(MaxButton::Included),
_ => Err(ErrorKind::Form(FormError::InvalidMaxButton {
value: value.to_string(),
})),
}
}
}
impl TryFrom<bool> for MaxButton {
type Error = ErrorKind;
fn try_from(value: bool) -> Result<Self, Self::Error> {
if value {
Ok(MaxButton::Included)
} else {
Ok(MaxButton::Excluded)
}
}
}
impl FromStr for MaxButton {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
MaxButton::try_from(s)
}
}
impl Display for MaxButton {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
MaxButton::Excluded => "Excluded",
MaxButton::Included => "Included",
};
write!(f, "{text}")
}
}
#[derive(
Debug,
PartialEq,
Eq,
Clone,
Default,
TryFromPrimitive,
serde::Serialize,
Copy,
Hash,
PartialOrd,
Ord,
)]
#[repr(i32)]
pub enum MinButton {
Excluded = 0,
#[default]
Included = -1,
}
impl FromStr for MinButton {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0" => Ok(MinButton::Excluded),
"-1" => Ok(MinButton::Included),
_ => Err(ErrorKind::Form(FormError::InvalidMinButton {
value: s.to_string(),
})),
}
}
}
impl TryFrom<bool> for MinButton {
type Error = ErrorKind;
fn try_from(value: bool) -> Result<Self, Self::Error> {
if value {
Ok(MinButton::Included)
} else {
Ok(MinButton::Excluded)
}
}
}
impl TryFrom<&str> for MinButton {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"0" => Ok(MinButton::Excluded),
"-1" => Ok(MinButton::Included),
_ => Err(ErrorKind::Form(FormError::InvalidMinButton {
value: value.to_string(),
})),
}
}
}
impl Display for MinButton {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
MinButton::Excluded => "Excluded",
MinButton::Included => "Included",
};
write!(f, "{text}")
}
}
#[derive(
Debug,
PartialEq,
Eq,
Clone,
Default,
TryFromPrimitive,
serde::Serialize,
Copy,
Hash,
PartialOrd,
Ord,
)]
#[repr(i32)]
pub enum WhatsThisButton {
Excluded = 0,
#[default]
Included = -1,
}
impl TryFrom<&str> for WhatsThisButton {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"0" => Ok(WhatsThisButton::Excluded),
"-1" => Ok(WhatsThisButton::Included),
_ => Err(ErrorKind::Form(FormError::InvalidWhatsThisButton {
value: value.to_string(),
})),
}
}
}
impl TryFrom<bool> for WhatsThisButton {
type Error = ErrorKind;
fn try_from(value: bool) -> Result<Self, Self::Error> {
if value {
Ok(WhatsThisButton::Included)
} else {
Ok(WhatsThisButton::Excluded)
}
}
}
impl Display for WhatsThisButton {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
WhatsThisButton::Excluded => "Excluded",
WhatsThisButton::Included => "Included",
};
write!(f, "{text}")
}
}
#[derive(
Debug,
PartialEq,
Eq,
Clone,
Default,
TryFromPrimitive,
serde::Serialize,
Copy,
Hash,
PartialOrd,
Ord,
)]
#[repr(i32)]
pub enum ShowInTaskbar {
Hide = 0,
#[default]
Show = -1,
}
impl TryFrom<&str> for ShowInTaskbar {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"0" => Ok(ShowInTaskbar::Hide),
"-1" => Ok(ShowInTaskbar::Show),
_ => Err(ErrorKind::Form(FormError::InvalidShowInTaskbar {
value: value.to_string(),
})),
}
}
}
impl FromStr for ShowInTaskbar {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
ShowInTaskbar::try_from(s)
}
}
impl TryFrom<bool> for ShowInTaskbar {
type Error = ErrorKind;
fn try_from(value: bool) -> Result<Self, Self::Error> {
if value {
Ok(ShowInTaskbar::Show)
} else {
Ok(ShowInTaskbar::Hide)
}
}
}
impl Display for ShowInTaskbar {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
ShowInTaskbar::Hide => "Hide",
ShowInTaskbar::Show => "Show",
};
write!(f, "{text}")
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct FormProperties {
pub appearance: Appearance,
pub auto_redraw: AutoRedraw,
pub back_color: Color,
pub border_style: FormBorderStyle,
pub caption: String,
pub client_height: i32,
pub client_left: i32,
pub client_top: i32,
pub client_width: i32,
pub clip_controls: ClipControls,
pub control_box: ControlBox,
pub draw_mode: DrawMode,
pub draw_style: DrawStyle,
pub draw_width: i32,
pub enabled: Activation,
pub fill_color: Color,
pub fill_style: FillStyle,
pub font_transparent: FontTransparency,
pub fore_color: Color,
pub has_dc: HasDeviceContext,
pub height: i32,
pub help_context_id: i32,
pub icon: Option<ReferenceOrValue<DynamicImage>>,
pub key_preview: bool,
pub left: i32,
pub link_mode: FormLinkMode,
pub link_topic: String,
pub max_button: MaxButton,
pub mdi_child: bool,
pub min_button: MinButton,
pub mouse_icon: Option<ReferenceOrValue<DynamicImage>>,
pub mouse_pointer: MousePointer,
pub moveable: Movability,
pub negotiate_menus: bool,
pub ole_drop_mode: OLEDropMode,
pub palette: Option<ReferenceOrValue<DynamicImage>>,
pub palette_mode: PaletteMode,
pub picture: Option<ReferenceOrValue<DynamicImage>>,
pub right_to_left: TextDirection,
pub scale_height: i32,
pub scale_left: i32,
pub scale_mode: ScaleMode,
pub scale_top: i32,
pub scale_width: i32,
pub show_in_taskbar: ShowInTaskbar,
pub start_up_position: StartUpPosition,
pub top: i32,
pub visible: Visibility,
pub whats_this_button: WhatsThisButton,
pub whats_this_help: WhatsThisHelp,
pub width: i32,
pub window_state: WindowState,
}
impl Serialize for FormProperties {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
use serde::ser::SerializeStruct;
let mut state = serializer.serialize_struct("FormProperties", 42)?;
state.serialize_field("appearance", &self.appearance)?;
state.serialize_field("auto_redraw", &self.auto_redraw)?;
state.serialize_field("back_color", &self.back_color)?;
state.serialize_field("border_style", &self.border_style)?;
state.serialize_field("caption", &self.caption)?;
state.serialize_field("client_height", &self.client_height)?;
state.serialize_field("client_left", &self.client_left)?;
state.serialize_field("client_top", &self.client_top)?;
state.serialize_field("client_width", &self.client_width)?;
state.serialize_field("clip_controls", &self.clip_controls)?;
state.serialize_field("control_box", &self.control_box)?;
state.serialize_field("draw_mode", &self.draw_mode)?;
state.serialize_field("draw_style", &self.draw_style)?;
state.serialize_field("draw_width", &self.draw_width)?;
state.serialize_field("enabled", &self.enabled)?;
state.serialize_field("fill_color", &self.fill_color)?;
state.serialize_field("fill_style", &self.fill_style)?;
state.serialize_field("font_transparent", &self.font_transparent)?;
state.serialize_field("fore_color", &self.fore_color)?;
state.serialize_field("has_dc", &self.has_dc)?;
state.serialize_field("height", &self.height)?;
state.serialize_field("help_context_id", &self.help_context_id)?;
let option_text = self.icon.as_ref().map(|_| "Some(DynamicImage)");
state.serialize_field("icon", &option_text)?;
state.serialize_field("key_preview", &self.key_preview)?;
state.serialize_field("left", &self.left)?;
state.serialize_field("link_mode", &self.link_mode)?;
state.serialize_field("link_topic", &self.link_topic)?;
state.serialize_field("max_button", &self.max_button)?;
state.serialize_field("mdi_child", &self.mdi_child)?;
state.serialize_field("min_button", &self.min_button)?;
let option_text = self.mouse_icon.as_ref().map(|_| "Some(DynamicImage)");
state.serialize_field("mouse_icon", &option_text)?;
state.serialize_field("mouse_pointer", &self.mouse_pointer)?;
state.serialize_field("moveable", &self.moveable)?;
state.serialize_field("negotiate_menus", &self.negotiate_menus)?;
state.serialize_field("ole_drop_mode", &self.ole_drop_mode)?;
let option_text = self.palette.as_ref().map(|_| "Some(DynamicImage)");
state.serialize_field("palette", &option_text)?;
state.serialize_field("palette_mode", &self.palette_mode)?;
let option_text = self.picture.as_ref().map(|_| "Some(DynamicImage)");
state.serialize_field("picture", &option_text)?;
state.serialize_field("right_to_left", &self.right_to_left)?;
state.serialize_field("scale_height", &self.scale_height)?;
state.serialize_field("scale_left", &self.scale_left)?;
state.serialize_field("scale_mode", &self.scale_mode)?;
state.serialize_field("scale_top", &self.scale_top)?;
state.serialize_field("scale_width", &self.scale_width)?;
state.serialize_field("show_in_taskbar", &self.show_in_taskbar)?;
state.serialize_field("start_up_position", &self.start_up_position)?;
state.serialize_field("top", &self.top)?;
state.serialize_field("visible", &self.visible)?;
state.serialize_field("whats_this_button", &self.whats_this_button)?;
state.serialize_field("whats_this_help", &self.whats_this_help)?;
state.serialize_field("width", &self.width)?;
state.serialize_field("window_state", &self.window_state)?;
state.end()
}
}
impl Default for FormProperties {
fn default() -> Self {
FormProperties {
appearance: Appearance::ThreeD,
auto_redraw: AutoRedraw::Manual,
back_color: VB_BUTTON_FACE,
border_style: FormBorderStyle::Sizable,
caption: "Form1".into(),
client_height: 200,
client_left: 0,
client_top: 0,
client_width: 300,
clip_controls: ClipControls::default(),
control_box: ControlBox::Included,
draw_mode: DrawMode::CopyPen,
draw_style: DrawStyle::Solid,
draw_width: 1,
enabled: Activation::Enabled,
fill_color: VB_SCROLL_BARS,
fill_style: FillStyle::Transparent,
font_transparent: FontTransparency::Transparent,
fore_color: VB_BUTTON_TEXT,
has_dc: HasDeviceContext::HasContext,
height: 240,
help_context_id: 0,
icon: None,
key_preview: false,
left: 0,
link_mode: FormLinkMode::None,
link_topic: String::new(),
max_button: MaxButton::Included,
mdi_child: false,
min_button: MinButton::Included,
mouse_icon: None,
mouse_pointer: MousePointer::Default,
moveable: Movability::Moveable,
negotiate_menus: true,
ole_drop_mode: OLEDropMode::default(),
palette: None,
palette_mode: PaletteMode::HalfTone,
picture: None,
right_to_left: TextDirection::LeftToRight,
scale_height: 240,
scale_left: 0,
scale_mode: ScaleMode::Twip,
scale_top: 0,
scale_width: 240,
show_in_taskbar: ShowInTaskbar::Show,
start_up_position: StartUpPosition::WindowsDefault,
top: 0,
visible: Visibility::Visible,
whats_this_button: WhatsThisButton::Excluded,
whats_this_help: WhatsThisHelp::F1Help,
width: 240,
window_state: WindowState::Normal,
}
}
}
impl From<Properties> for FormProperties {
fn from(prop: Properties) -> Self {
let mut form_prop = FormProperties::default();
form_prop.appearance = prop.get_property("Appearance", form_prop.appearance);
form_prop.auto_redraw = prop.get_property("AutoRedraw", form_prop.auto_redraw);
form_prop.back_color = prop.get_color("BackColor", form_prop.back_color);
form_prop.border_style = prop.get_property("BorderStyle", form_prop.border_style);
form_prop.caption = match prop.get("Caption") {
Some(caption) => caption.clone(),
None => form_prop.caption,
};
form_prop.client_height = prop.get_i32("ClientHeight", form_prop.client_height);
form_prop.client_left = prop.get_i32("ClientLeft", form_prop.client_left);
form_prop.client_top = prop.get_i32("ClientTop", form_prop.client_top);
form_prop.client_width = prop.get_i32("ClientWidth", form_prop.client_width);
form_prop.clip_controls = prop.get_property("ClipControls", form_prop.clip_controls);
form_prop.control_box = prop.get_property("ControlBox", form_prop.control_box);
form_prop.draw_mode = prop.get_property("DrawMode", form_prop.draw_mode);
form_prop.draw_style = prop.get_property("DrawStyle", form_prop.draw_style);
form_prop.draw_width = prop.get_i32("DrawWidth", form_prop.draw_width);
form_prop.enabled = prop.get_property("Enabled", form_prop.enabled);
form_prop.fill_color = prop.get_color("FillColor", form_prop.fill_color);
form_prop.fill_style = prop.get_property("FillStyle", form_prop.fill_style);
form_prop.font_transparent =
prop.get_property("FontTransparent", form_prop.font_transparent);
form_prop.fore_color = prop.get_color("ForeColor", form_prop.fore_color);
form_prop.has_dc = prop.get_property("HasDC", form_prop.has_dc);
form_prop.height = prop.get_i32("Height", form_prop.height);
form_prop.help_context_id = prop.get_i32("HelpContextID", form_prop.help_context_id);
form_prop.key_preview = prop.get_bool("KeyPreview", form_prop.key_preview);
form_prop.left = prop.get_i32("Left", form_prop.left);
form_prop.link_mode = prop.get_property("LinkMode", form_prop.link_mode);
form_prop.link_topic = match prop.get("LinkTopic") {
Some(link_topic) => link_topic.clone(),
None => form_prop.link_topic,
};
form_prop.max_button = prop.get_property("MaxButton", form_prop.max_button);
form_prop.mdi_child = prop.get_bool("MDIChild", form_prop.mdi_child);
form_prop.min_button = prop.get_property("MinButton", form_prop.min_button);
form_prop.mouse_pointer = prop.get_property("MousePointer", form_prop.mouse_pointer);
form_prop.moveable = prop.get_property("Moveable", form_prop.moveable);
form_prop.negotiate_menus = prop.get_bool("NegotiateMenus", form_prop.negotiate_menus);
form_prop.ole_drop_mode = prop.get_property("OLEDropMode", form_prop.ole_drop_mode);
form_prop.palette_mode = prop.get_property("PaletteMode", form_prop.palette_mode);
form_prop.right_to_left = prop.get_property("RightToLeft", form_prop.right_to_left);
form_prop.scale_height = prop.get_i32("ScaleHeight", form_prop.scale_height);
form_prop.scale_left = prop.get_i32("ScaleLeft", form_prop.scale_left);
form_prop.scale_mode = prop.get_property("ScaleMode", form_prop.scale_mode);
form_prop.scale_top = prop.get_i32("ScaleTop", form_prop.scale_top);
form_prop.scale_width = prop.get_i32("ScaleWidth", form_prop.scale_width);
form_prop.show_in_taskbar = prop.get_property("ShowInTaskbar", form_prop.show_in_taskbar);
form_prop.start_up_position =
prop.get_startup_position("StartUpPosition", form_prop.start_up_position);
form_prop.top = prop.get_i32("Top", form_prop.top);
form_prop.visible = prop.get_property("Visible", form_prop.visible);
form_prop.whats_this_button =
prop.get_property("WhatsThisButton", form_prop.whats_this_button);
form_prop.whats_this_help = prop.get_property("WhatsThisHelp", form_prop.whats_this_help);
form_prop.width = prop.get_i32("Width", form_prop.width);
form_prop.window_state = prop.get_property("WindowState", form_prop.window_state);
form_prop
}
}