use std::convert::TryFrom;
use std::fmt::Display;
use std::str::FromStr;
use crate::errors::{FormError, ErrorKind};
use crate::files::common::Properties;
use crate::language::controls::{Activation, Visibility};
use num_enum::TryFromPrimitive;
use serde::Serialize;
#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
pub struct MenuControl {
name: String,
tag: String,
index: i32,
properties: MenuProperties,
sub_menus: Vec<MenuControl>,
}
impl MenuControl {
#[must_use]
pub fn new(
name: String,
tag: String,
index: i32,
properties: MenuProperties,
sub_menus: Vec<MenuControl>,
) -> Self {
Self {
name,
tag,
index,
properties,
sub_menus,
}
}
#[must_use]
pub fn name(&self) -> &str {
&self.name
}
#[must_use]
pub fn tag(&self) -> &str {
&self.tag
}
#[must_use]
pub fn index(&self) -> i32 {
self.index
}
#[must_use]
pub fn properties(&self) -> &MenuProperties {
&self.properties
}
#[must_use]
pub fn sub_menus(&self) -> &[MenuControl] {
&self.sub_menus
}
#[must_use]
pub fn into_name(self) -> String {
self.name
}
#[must_use]
pub fn into_tag(self) -> String {
self.tag
}
#[must_use]
pub fn into_properties(self) -> MenuProperties {
self.properties
}
#[must_use]
pub fn into_sub_menus(self) -> Vec<MenuControl> {
self.sub_menus
}
#[must_use]
pub fn into_parts(self) -> (String, String, i32, MenuProperties, Vec<MenuControl>) {
(
self.name,
self.tag,
self.index,
self.properties,
self.sub_menus,
)
}
}
impl Display for MenuControl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "MenuControl: {}", self.name)
}
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
pub struct MenuProperties {
pub caption: String,
pub checked: bool,
pub enabled: Activation,
pub help_context_id: i32,
pub negotiate_position: NegotiatePosition,
pub shortcut: Option<ShortCut>,
pub visible: Visibility,
pub window_list: bool,
}
impl Default for MenuProperties {
fn default() -> Self {
MenuProperties {
caption: String::new(),
checked: false,
enabled: Activation::Enabled,
help_context_id: 0,
negotiate_position: NegotiatePosition::None,
shortcut: None,
visible: Visibility::Visible,
window_list: false,
}
}
}
impl From<Properties> for MenuProperties {
fn from(prop: Properties) -> Self {
let mut menu_prop = MenuProperties::default();
menu_prop.caption = match prop.get("Caption") {
Some(caption) => caption.into(),
None => menu_prop.caption,
};
menu_prop.checked = prop.get_bool("Checked", menu_prop.checked);
menu_prop.enabled = prop.get_property("Enabled", menu_prop.enabled);
menu_prop.help_context_id = prop.get_i32("HelpContextID", menu_prop.help_context_id);
menu_prop.negotiate_position =
prop.get_property("NegotiationPosition", menu_prop.negotiate_position);
menu_prop.shortcut = prop.get_option("Shortcut", menu_prop.shortcut);
menu_prop.visible = prop.get_property("Visible", menu_prop.visible);
menu_prop.window_list = prop.get_bool("WindowList", menu_prop.window_list);
menu_prop
}
}
#[derive(
Debug, PartialEq, Eq, Clone, Serialize, TryFromPrimitive, Default, Copy, Hash, PartialOrd, Ord,
)]
#[repr(i32)]
pub enum NegotiatePosition {
#[default]
None = 0,
Left = 1,
Middle = 2,
Right = 3,
}
impl FromStr for NegotiatePosition {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0" => Ok(NegotiatePosition::None),
"1" => Ok(NegotiatePosition::Left),
"2" => Ok(NegotiatePosition::Middle),
"3" => Ok(NegotiatePosition::Right),
_ => Err(ErrorKind::Form(FormError::InvalidNegotiatePosition {
value: s.to_string(),
})),
}
}
}
impl TryFrom<&str> for NegotiatePosition {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
NegotiatePosition::from_str(value)
}
}
impl Display for NegotiatePosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
NegotiatePosition::None => "None",
NegotiatePosition::Left => "Left",
NegotiatePosition::Middle => "Middle",
NegotiatePosition::Right => "Right",
};
write!(f, "{text}")
}
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Copy, Hash, PartialOrd, Ord)]
pub enum ShortCut {
CtrlA,
CtrlB,
CtrlC,
CtrlD,
CtrlE,
CtrlF,
CtrlG,
CtrlH,
CtrlI,
CtrlJ,
CtrlK,
CtrlL,
CtrlM,
CtrlN,
CtrlO,
CtrlP,
CtrlQ,
CtrlR,
CtrlS,
CtrlT,
CtrlU,
CtrlV,
CtrlW,
CtrlX,
CtrlY,
CtrlZ,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F11,
F12,
CtrlF1,
CtrlF2,
CtrlF3,
CtrlF4,
CtrlF5,
CtrlF6,
CtrlF7,
CtrlF8,
CtrlF9,
CtrlF11,
CtrlF12,
ShiftF1,
ShiftF2,
ShiftF3,
ShiftF4,
ShiftF5,
ShiftF6,
ShiftF7,
ShiftF8,
ShiftF9,
ShiftF11,
ShiftF12,
ShiftCtrlF1,
ShiftCtrlF2,
ShiftCtrlF3,
ShiftCtrlF4,
ShiftCtrlF5,
ShiftCtrlF6,
ShiftCtrlF7,
ShiftCtrlF8,
ShiftCtrlF9,
ShiftCtrlF11,
ShiftCtrlF12,
CtrlIns,
ShiftIns,
Del,
ShiftDel,
AltBKsp,
}
impl Display for ShortCut {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
ShortCut::CtrlA => "Ctrl+A",
ShortCut::CtrlB => "Ctrl+B",
ShortCut::CtrlC => "Ctrl+C",
ShortCut::CtrlD => "Ctrl+D",
ShortCut::CtrlE => "Ctrl+E",
ShortCut::CtrlF => "Ctrl+F",
ShortCut::CtrlG => "Ctrl+G",
ShortCut::CtrlH => "Ctrl+H",
ShortCut::CtrlI => "Ctrl+I",
ShortCut::CtrlJ => "Ctrl+J",
ShortCut::CtrlK => "Ctrl+K",
ShortCut::CtrlL => "Ctrl+L",
ShortCut::CtrlM => "Ctrl+M",
ShortCut::CtrlN => "Ctrl+N",
ShortCut::CtrlO => "Ctrl+O",
ShortCut::CtrlP => "Ctrl+P",
ShortCut::CtrlQ => "Ctrl+Q",
ShortCut::CtrlR => "Ctrl+R",
ShortCut::CtrlS => "Ctrl+S",
ShortCut::CtrlT => "Ctrl+T",
ShortCut::CtrlU => "Ctrl+U",
ShortCut::CtrlV => "Ctrl+V",
ShortCut::CtrlW => "Ctrl+W",
ShortCut::CtrlX => "Ctrl+X",
ShortCut::CtrlY => "Ctrl+Y",
ShortCut::CtrlZ => "Ctrl+Z",
ShortCut::F1 => "F1",
ShortCut::F2 => "F2",
ShortCut::F3 => "F3",
ShortCut::F4 => "F4",
ShortCut::F5 => "F5",
ShortCut::F6 => "F6",
ShortCut::F7 => "F7",
ShortCut::F8 => "F8",
ShortCut::F9 => "F9",
ShortCut::F11 => "F11",
ShortCut::F12 => "F12",
ShortCut::CtrlF1 => "Ctrl+F1",
ShortCut::CtrlF2 => "Ctrl+F2",
ShortCut::CtrlF3 => "Ctrl+F3",
ShortCut::CtrlF4 => "Ctrl+F4",
ShortCut::CtrlF5 => "Ctrl+F5",
ShortCut::CtrlF6 => "Ctrl+F6",
ShortCut::CtrlF7 => "Ctrl+F7",
ShortCut::CtrlF8 => "Ctrl+F8",
ShortCut::CtrlF9 => "Ctrl+F9",
ShortCut::CtrlF11 => "Ctrl+F11",
ShortCut::CtrlF12 => "Ctrl+F12",
ShortCut::ShiftF1 => "Shift+F1",
ShortCut::ShiftF2 => "Shift+F2",
ShortCut::ShiftF3 => "Shift+F3",
ShortCut::ShiftF4 => "Shift+F4",
ShortCut::ShiftF5 => "Shift+F5",
ShortCut::ShiftF6 => "Shift+F6",
ShortCut::ShiftF7 => "Shift+F7",
ShortCut::ShiftF8 => "Shift+F8",
ShortCut::ShiftF9 => "Shift+F9",
ShortCut::ShiftF11 => "Shift+F11",
ShortCut::ShiftF12 => "Shift+F12",
ShortCut::ShiftCtrlF1 => "Shift+Ctrl+F1",
ShortCut::ShiftCtrlF2 => "Shift+Ctrl+F2",
ShortCut::ShiftCtrlF3 => "Shift+Ctrl+F3",
ShortCut::ShiftCtrlF4 => "Shift+Ctrl+F4",
ShortCut::ShiftCtrlF5 => "Shift+Ctrl+F5",
ShortCut::ShiftCtrlF6 => "Shift+Ctrl+F6",
ShortCut::ShiftCtrlF7 => "Shift+Ctrl+F7",
ShortCut::ShiftCtrlF8 => "Shift+Ctrl+F8",
ShortCut::ShiftCtrlF9 => "Shift+Ctrl+F9",
ShortCut::ShiftCtrlF11 => "Shift+Ctrl+F11",
ShortCut::ShiftCtrlF12 => "Shift+Ctrl+F12",
ShortCut::CtrlIns => "Ctrl+Insert",
ShortCut::ShiftIns => "Shift+Insert",
ShortCut::Del => "Delete",
ShortCut::ShiftDel => "Shift+Delete",
ShortCut::AltBKsp => "Alt+Backspace",
};
write!(f, "{text}")
}
}
impl FromStr for ShortCut {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
ShortCut::try_from(s)
}
}
impl TryFrom<&str> for ShortCut {
type Error = ErrorKind;
fn try_from(s: &str) -> Result<Self, ErrorKind> {
match s {
"^A" => Ok(ShortCut::CtrlA),
"^B" => Ok(ShortCut::CtrlB),
"^C" => Ok(ShortCut::CtrlC),
"^D" => Ok(ShortCut::CtrlD),
"^E" => Ok(ShortCut::CtrlE),
"^F" => Ok(ShortCut::CtrlF),
"^G" => Ok(ShortCut::CtrlG),
"^H" => Ok(ShortCut::CtrlH),
"^I" => Ok(ShortCut::CtrlI),
"^J" => Ok(ShortCut::CtrlJ),
"^K" => Ok(ShortCut::CtrlK),
"^L" => Ok(ShortCut::CtrlL),
"^M" => Ok(ShortCut::CtrlM),
"^N" => Ok(ShortCut::CtrlN),
"^O" => Ok(ShortCut::CtrlO),
"^P" => Ok(ShortCut::CtrlP),
"^Q" => Ok(ShortCut::CtrlQ),
"^R" => Ok(ShortCut::CtrlR),
"^S" => Ok(ShortCut::CtrlS),
"^T" => Ok(ShortCut::CtrlT),
"^U" => Ok(ShortCut::CtrlU),
"^V" => Ok(ShortCut::CtrlV),
"^W" => Ok(ShortCut::CtrlW),
"^X" => Ok(ShortCut::CtrlX),
"^Y" => Ok(ShortCut::CtrlY),
"^Z" => Ok(ShortCut::CtrlZ),
"{F1}" => Ok(ShortCut::F1),
"{F2}" => Ok(ShortCut::F2),
"{F3}" => Ok(ShortCut::F3),
"{F4}" => Ok(ShortCut::F4),
"{F5}" => Ok(ShortCut::F5),
"{F6}" => Ok(ShortCut::F6),
"{F7}" => Ok(ShortCut::F7),
"{F8}" => Ok(ShortCut::F8),
"{F9}" => Ok(ShortCut::F9),
"{F11}" => Ok(ShortCut::F11),
"{F12}" => Ok(ShortCut::F12),
"^{F1}" => Ok(ShortCut::CtrlF1),
"^{F2}" => Ok(ShortCut::CtrlF2),
"^{F3}" => Ok(ShortCut::CtrlF3),
"^{F4}" => Ok(ShortCut::CtrlF4),
"^{F5}" => Ok(ShortCut::CtrlF5),
"^{F6}" => Ok(ShortCut::CtrlF6),
"^{F7}" => Ok(ShortCut::CtrlF7),
"^{F8}" => Ok(ShortCut::CtrlF8),
"^{F9}" => Ok(ShortCut::CtrlF9),
"^{F11}" => Ok(ShortCut::CtrlF11),
"^{F12}" => Ok(ShortCut::CtrlF12),
"+{F1}" => Ok(ShortCut::ShiftF1),
"+{F2}" => Ok(ShortCut::ShiftF2),
"+{F3}" => Ok(ShortCut::ShiftF3),
"+{F4}" => Ok(ShortCut::ShiftF4),
"+{F5}" => Ok(ShortCut::ShiftF5),
"+{F6}" => Ok(ShortCut::ShiftF6),
"+{F7}" => Ok(ShortCut::ShiftF7),
"+{F8}" => Ok(ShortCut::ShiftF8),
"+{F9}" => Ok(ShortCut::ShiftF9),
"+{F11}" => Ok(ShortCut::ShiftF11),
"+{F12}" => Ok(ShortCut::ShiftF12),
"+^{F1}" => Ok(ShortCut::ShiftCtrlF1),
"+^{F2}" => Ok(ShortCut::ShiftCtrlF2),
"+^{F3}" => Ok(ShortCut::ShiftCtrlF3),
"+^{F4}" => Ok(ShortCut::ShiftCtrlF4),
"+^{F5}" => Ok(ShortCut::ShiftCtrlF5),
"+^{F6}" => Ok(ShortCut::ShiftCtrlF6),
"+^{F7}" => Ok(ShortCut::ShiftCtrlF7),
"+^{F8}" => Ok(ShortCut::ShiftCtrlF8),
"+^{F9}" => Ok(ShortCut::ShiftCtrlF9),
"+^{F11}" => Ok(ShortCut::ShiftCtrlF11),
"+^{F12}" => Ok(ShortCut::ShiftCtrlF12),
"^{INSERT}" => Ok(ShortCut::CtrlIns),
"+{INSERT}" => Ok(ShortCut::ShiftIns),
"{DEL}" => Ok(ShortCut::Del),
"+{DEL}" => Ok(ShortCut::ShiftDel),
"%{BKSP}" => Ok(ShortCut::AltBKsp),
_ => Err(ErrorKind::Form(FormError::ShortCutUnparsable)),
}
}
}