729 lines
20 KiB
Rust
729 lines
20 KiB
Rust
//! Statische Forms-Typinformation. Namen werden beim Übersetzen in diese
|
|
//! Tabellenindizes aufgelöst; die Laufzeit muss keine Strings durchsuchen.
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub enum ObjectClass {
|
|
Form,
|
|
CheckBox,
|
|
ComboBox,
|
|
CommandButton,
|
|
DirListBox,
|
|
DriveListBox,
|
|
FileListBox,
|
|
Frame,
|
|
HScrollBar,
|
|
Label,
|
|
ListBox,
|
|
Menu,
|
|
OptionButton,
|
|
PictureBox,
|
|
TextBox,
|
|
Timer,
|
|
VScrollBar,
|
|
Screen,
|
|
Spin,
|
|
}
|
|
|
|
impl ObjectClass {
|
|
pub const ALL: [Self; 19] = [
|
|
Self::Form,
|
|
Self::CheckBox,
|
|
Self::ComboBox,
|
|
Self::CommandButton,
|
|
Self::DirListBox,
|
|
Self::DriveListBox,
|
|
Self::FileListBox,
|
|
Self::Frame,
|
|
Self::HScrollBar,
|
|
Self::Label,
|
|
Self::ListBox,
|
|
Self::Menu,
|
|
Self::OptionButton,
|
|
Self::PictureBox,
|
|
Self::TextBox,
|
|
Self::Timer,
|
|
Self::VScrollBar,
|
|
Self::Screen,
|
|
Self::Spin,
|
|
];
|
|
|
|
pub fn name(self) -> &'static str {
|
|
match self {
|
|
Self::Form => "FORM",
|
|
Self::CheckBox => "CHECKBOX",
|
|
Self::ComboBox => "COMBOBOX",
|
|
Self::CommandButton => "COMMANDBUTTON",
|
|
Self::DirListBox => "DIRLISTBOX",
|
|
Self::DriveListBox => "DRIVELISTBOX",
|
|
Self::FileListBox => "FILELISTBOX",
|
|
Self::Frame => "FRAME",
|
|
Self::HScrollBar => "HSCROLLBAR",
|
|
Self::Label => "LABEL",
|
|
Self::ListBox => "LISTBOX",
|
|
Self::Menu => "MENU",
|
|
Self::OptionButton => "OPTIONBUTTON",
|
|
Self::PictureBox => "PICTUREBOX",
|
|
Self::TextBox => "TEXTBOX",
|
|
Self::Timer => "TIMER",
|
|
Self::VScrollBar => "VSCROLLBAR",
|
|
Self::Screen => "SCREEN",
|
|
Self::Spin => "SPIN",
|
|
}
|
|
}
|
|
|
|
pub fn display_name(self) -> &'static str {
|
|
match self {
|
|
Self::Form => "Form",
|
|
Self::CheckBox => "CheckBox",
|
|
Self::ComboBox => "ComboBox",
|
|
Self::CommandButton => "CommandButton",
|
|
Self::DirListBox => "DirListBox",
|
|
Self::DriveListBox => "DriveListBox",
|
|
Self::FileListBox => "FileListBox",
|
|
Self::Frame => "Frame",
|
|
Self::HScrollBar => "HScrollBar",
|
|
Self::Label => "Label",
|
|
Self::ListBox => "ListBox",
|
|
Self::Menu => "Menu",
|
|
Self::OptionButton => "OptionButton",
|
|
Self::PictureBox => "PictureBox",
|
|
Self::TextBox => "TextBox",
|
|
Self::Timer => "Timer",
|
|
Self::VScrollBar => "VScrollBar",
|
|
Self::Screen => "Screen",
|
|
Self::Spin => "Spin",
|
|
}
|
|
}
|
|
|
|
pub fn parse(name: &str) -> Option<Self> {
|
|
Self::ALL
|
|
.into_iter()
|
|
.find(|c| c.name().eq_ignore_ascii_case(name))
|
|
}
|
|
|
|
pub fn id(self) -> u8 {
|
|
Self::ALL.iter().position(|c| *c == self).unwrap() as u8
|
|
}
|
|
|
|
pub fn from_id(id: u8) -> Option<Self> {
|
|
Self::ALL.get(id as usize).copied()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum PropertyType {
|
|
Integer,
|
|
Single,
|
|
String,
|
|
Boolean,
|
|
Object,
|
|
IntegerArray,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub enum PropertyDefault {
|
|
Integer(i32),
|
|
Single(f32),
|
|
String(&'static str),
|
|
Boolean(bool),
|
|
Empty,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub struct PropertySpec {
|
|
pub name: &'static str,
|
|
pub ty: PropertyType,
|
|
pub default: PropertyDefault,
|
|
pub min: Option<i32>,
|
|
pub max: Option<i32>,
|
|
pub writable: bool,
|
|
}
|
|
|
|
const fn int(name: &'static str, default: i32) -> PropertySpec {
|
|
PropertySpec {
|
|
name,
|
|
ty: PropertyType::Integer,
|
|
default: PropertyDefault::Integer(default),
|
|
min: None,
|
|
max: None,
|
|
writable: true,
|
|
}
|
|
}
|
|
const fn range(name: &'static str, default: i32, min: i32, max: i32) -> PropertySpec {
|
|
PropertySpec {
|
|
name,
|
|
ty: PropertyType::Integer,
|
|
default: PropertyDefault::Integer(default),
|
|
min: Some(min),
|
|
max: Some(max),
|
|
writable: true,
|
|
}
|
|
}
|
|
const fn boolp(name: &'static str, default: bool) -> PropertySpec {
|
|
PropertySpec {
|
|
name,
|
|
ty: PropertyType::Boolean,
|
|
default: PropertyDefault::Boolean(default),
|
|
min: None,
|
|
max: None,
|
|
writable: true,
|
|
}
|
|
}
|
|
const fn string(name: &'static str, default: &'static str) -> PropertySpec {
|
|
PropertySpec {
|
|
name,
|
|
ty: PropertyType::String,
|
|
default: PropertyDefault::String(default),
|
|
min: None,
|
|
max: None,
|
|
writable: true,
|
|
}
|
|
}
|
|
const fn ro(name: &'static str, ty: PropertyType) -> PropertySpec {
|
|
PropertySpec {
|
|
name,
|
|
ty,
|
|
default: PropertyDefault::Empty,
|
|
min: None,
|
|
max: None,
|
|
writable: false,
|
|
}
|
|
}
|
|
|
|
/// Eigenschaftstabelle in stabiler Reihenfolge. Der Vektor ist klein und wird
|
|
/// nur beim Übersetzen bzw. Erzeugen eines Objekts aufgebaut.
|
|
pub fn properties(class: ObjectClass) -> Vec<PropertySpec> {
|
|
use ObjectClass::*;
|
|
let mut p = Vec::new();
|
|
if !matches!(class, Timer | Menu | Screen) {
|
|
p.extend([
|
|
range("BACKCOLOR", 7, 0, 15),
|
|
boolp("ENABLED", true),
|
|
range("HEIGHT", 1, 1, 254),
|
|
range("LEFT", 0, 0, 254),
|
|
range("MOUSEPOINTER", 0, 0, 12),
|
|
ro("PARENT", PropertyType::Object),
|
|
string("TAG", ""),
|
|
range("TOP", 0, 0, 254),
|
|
boolp("VISIBLE", true),
|
|
range("WIDTH", 1, 1, 254),
|
|
]);
|
|
}
|
|
if !matches!(class, Form | Timer | Menu | Screen) {
|
|
p.push(int("INDEX", 0));
|
|
p.push(int("TABINDEX", 0));
|
|
}
|
|
if !matches!(class, Form | Frame | Label | Timer | Menu | Screen) {
|
|
p.push(boolp("TABSTOP", true));
|
|
}
|
|
if !matches!(class, Form | Timer | Menu | Screen) {
|
|
p.push(string("CTLNAME", ""));
|
|
}
|
|
if matches!(
|
|
class,
|
|
Form | TextBox
|
|
| ListBox
|
|
| ComboBox
|
|
| CheckBox
|
|
| OptionButton
|
|
| Label
|
|
| HScrollBar
|
|
| VScrollBar
|
|
| PictureBox
|
|
) {
|
|
p.push(range("FORECOLOR", 0, 0, 15));
|
|
}
|
|
if matches!(
|
|
class,
|
|
Form | CommandButton
|
|
| TextBox
|
|
| ListBox
|
|
| ComboBox
|
|
| CheckBox
|
|
| OptionButton
|
|
| Frame
|
|
| Label
|
|
| HScrollBar
|
|
| VScrollBar
|
|
| PictureBox
|
|
) {
|
|
p.push(range("DRAGMODE", 0, 0, 1));
|
|
}
|
|
match class {
|
|
Form => p.extend([
|
|
boolp("AUTOREDRAW", false),
|
|
range("BORDERSTYLE", 2, 0, 6),
|
|
string("CAPTION", ""),
|
|
boolp("CONTROLBOX", true),
|
|
int("CURRENTX", 0),
|
|
int("CURRENTY", 0),
|
|
string("FORMNAME", ""),
|
|
range("FORMTYPE", 0, 0, 1),
|
|
boolp("MAXBUTTON", true),
|
|
boolp("MINBUTTON", true),
|
|
ro("SCALEHEIGHT", PropertyType::Integer),
|
|
ro("SCALEWIDTH", PropertyType::Integer),
|
|
range("WINDOWSTATE", 0, 0, 2),
|
|
]),
|
|
CommandButton => p.extend([
|
|
boolp("CANCEL", false),
|
|
string("CAPTION", ""),
|
|
boolp("DEFAULT", false),
|
|
boolp("VALUE", false),
|
|
]),
|
|
TextBox => p.extend([
|
|
range("BORDERSTYLE", 1, 0, 1),
|
|
boolp("MULTILINE", false),
|
|
range("SCROLLBARS", 0, 0, 3),
|
|
int("SELLENGTH", 0),
|
|
int("SELSTART", 0),
|
|
string("SELTEXT", ""),
|
|
string("TEXT", ""),
|
|
]),
|
|
ListBox => p.extend([
|
|
ro("LIST", PropertyType::String),
|
|
ro("LISTCOUNT", PropertyType::Integer),
|
|
int("LISTINDEX", -1),
|
|
boolp("SORTED", false),
|
|
string("TEXT", ""),
|
|
]),
|
|
ComboBox => p.extend([
|
|
ro("LIST", PropertyType::String),
|
|
ro("LISTCOUNT", PropertyType::Integer),
|
|
int("LISTINDEX", -1),
|
|
boolp("SORTED", false),
|
|
int("SELLENGTH", 0),
|
|
int("SELSTART", 0),
|
|
string("SELTEXT", ""),
|
|
range("STYLE", 0, 0, 2),
|
|
string("TEXT", ""),
|
|
]),
|
|
CheckBox => p.extend([string("CAPTION", ""), range("VALUE", 0, 0, 2)]),
|
|
OptionButton => p.extend([string("CAPTION", ""), range("VALUE", 0, -1, 1)]),
|
|
Frame => p.push(string("CAPTION", "")),
|
|
Label => p.extend([
|
|
range("ALIGNMENT", 0, 0, 2),
|
|
boolp("AUTOSIZE", false),
|
|
range("BORDERSTYLE", 0, 0, 2),
|
|
string("CAPTION", ""),
|
|
]),
|
|
HScrollBar | VScrollBar => p.extend([
|
|
ro("ATTACHED", PropertyType::Boolean),
|
|
range("LARGECHANGE", 1, 1, 32767),
|
|
range("MIN", 0, -32768, 32767),
|
|
range("MAX", 32767, -32768, 32767),
|
|
range("SMALLCHANGE", 1, 1, 32767),
|
|
range("VALUE", 0, -32768, 32767),
|
|
]),
|
|
Spin => {
|
|
p.extend([
|
|
ro("BORDERSTYLE", PropertyType::Integer),
|
|
range("INTERVAL", 250, 0, 65535),
|
|
range("MIN", 0, -32768, 32767),
|
|
range("MAX", 32767, -32768, 32767),
|
|
range("STYLE", 0, 0, 1),
|
|
range("VALUE", 0, -32768, 32767),
|
|
]);
|
|
for name in ["HEIGHT", "WIDTH"] {
|
|
if let Some(property) = p.iter_mut().find(|property| property.name == name) {
|
|
property.writable = false;
|
|
}
|
|
}
|
|
}
|
|
PictureBox => p.extend([
|
|
boolp("AUTOREDRAW", false),
|
|
range("BORDERSTYLE", 1, 0, 2),
|
|
int("CURRENTX", 0),
|
|
int("CURRENTY", 0),
|
|
ro("SCALEHEIGHT", PropertyType::Integer),
|
|
ro("SCALEWIDTH", PropertyType::Integer),
|
|
]),
|
|
Timer => p.extend([
|
|
string("CTLNAME", ""),
|
|
boolp("ENABLED", true),
|
|
int("INDEX", 0),
|
|
range("INTERVAL", 0, 0, 65535),
|
|
ro("PARENT", PropertyType::Object),
|
|
string("TAG", ""),
|
|
]),
|
|
Menu => p.extend([
|
|
string("CAPTION", ""),
|
|
boolp("CHECKED", false),
|
|
string("CTLNAME", ""),
|
|
boolp("ENABLED", true),
|
|
int("INDEX", 0),
|
|
ro("PARENT", PropertyType::Object),
|
|
boolp("SEPARATOR", false),
|
|
string("TAG", ""),
|
|
boolp("VISIBLE", true),
|
|
string("SHORTCUT", ""),
|
|
]),
|
|
DirListBox => p.extend([
|
|
ro("LIST", PropertyType::String),
|
|
ro("LISTCOUNT", PropertyType::Integer),
|
|
int("LISTINDEX", -1),
|
|
string("PATH", ""),
|
|
string("TEXT", ""),
|
|
]),
|
|
DriveListBox => p.extend([
|
|
ro("LIST", PropertyType::String),
|
|
ro("LISTCOUNT", PropertyType::Integer),
|
|
int("LISTINDEX", -1),
|
|
string("DRIVE", ""),
|
|
string("TEXT", ""),
|
|
]),
|
|
FileListBox => p.extend([
|
|
ro("LIST", PropertyType::String),
|
|
ro("LISTCOUNT", PropertyType::Integer),
|
|
int("LISTINDEX", -1),
|
|
string("FILENAME", ""),
|
|
string("PATH", ""),
|
|
string("PATTERN", "*.*"),
|
|
boolp("ARCHIVE", true),
|
|
boolp("HIDDEN", false),
|
|
boolp("NORMAL", true),
|
|
boolp("READONLY", true),
|
|
boolp("SYSTEM", false),
|
|
string("TEXT", ""),
|
|
]),
|
|
Screen => p.extend([
|
|
ro("ACTIVECONTROL", PropertyType::Object),
|
|
ro("ACTIVEFORM", PropertyType::Object),
|
|
boolp("AUTOREDRAW", false),
|
|
PropertySpec {
|
|
name: "CONTROLPANEL",
|
|
ty: PropertyType::IntegerArray,
|
|
default: PropertyDefault::Integer(0),
|
|
min: Some(0),
|
|
max: Some(15),
|
|
writable: true,
|
|
},
|
|
ro("HEIGHT", PropertyType::Integer),
|
|
ro("WIDTH", PropertyType::Integer),
|
|
range("MOUSEPOINTER", 0, 0, 12),
|
|
]),
|
|
}
|
|
if class == Form {
|
|
if let Some(visible) = p.iter_mut().find(|p| p.name == "VISIBLE") {
|
|
visible.default = PropertyDefault::Boolean(false);
|
|
}
|
|
}
|
|
p
|
|
}
|
|
|
|
pub fn property(class: ObjectClass, name: &str) -> Option<(u16, PropertySpec)> {
|
|
properties(class)
|
|
.into_iter()
|
|
.enumerate()
|
|
.find(|(_, p)| p.name.eq_ignore_ascii_case(name))
|
|
.map(|(i, p)| (i as u16, p))
|
|
}
|
|
|
|
pub fn methods(class: ObjectClass) -> &'static [&'static str] {
|
|
use ObjectClass::*;
|
|
match class {
|
|
Form => &[
|
|
"CLS",
|
|
"DRAG",
|
|
"HIDE",
|
|
"LOAD",
|
|
"MOVE",
|
|
"PRINT",
|
|
"PRINTFORM",
|
|
"REFRESH",
|
|
"SHOW",
|
|
"TEXTHEIGHT",
|
|
"TEXTWIDTH",
|
|
"UNLOAD",
|
|
],
|
|
ListBox | ComboBox => &[
|
|
"ADDITEM",
|
|
"DRAG",
|
|
"MOVE",
|
|
"REFRESH",
|
|
"REMOVEITEM",
|
|
"SETFOCUS",
|
|
],
|
|
CommandButton | TextBox | CheckBox | OptionButton => {
|
|
&["DRAG", "MOVE", "REFRESH", "SETFOCUS"]
|
|
}
|
|
Frame | Label | HScrollBar | VScrollBar => &["DRAG", "MOVE", "REFRESH"],
|
|
Spin => &["DRAG", "REFRESH", "SETFOCUS"],
|
|
PictureBox => &[
|
|
"CLS",
|
|
"DRAG",
|
|
"MOVE",
|
|
"PRINT",
|
|
"REFRESH",
|
|
"SETFOCUS",
|
|
"TEXTHEIGHT",
|
|
"TEXTWIDTH",
|
|
],
|
|
Screen => &["HIDE", "SHOW"],
|
|
_ => &[],
|
|
}
|
|
}
|
|
|
|
pub fn method_is_implemented(class: ObjectClass, name: &str) -> bool {
|
|
methods(class).contains(&name)
|
|
}
|
|
|
|
pub fn method_arity(class: ObjectClass, name: &str) -> Option<(usize, usize)> {
|
|
match (class, name) {
|
|
(ObjectClass::Form, "SHOW") => Some((0, 1)),
|
|
(ObjectClass::Form, "HIDE" | "LOAD" | "UNLOAD")
|
|
| (ObjectClass::Screen, "HIDE" | "SHOW") => Some((0, 0)),
|
|
(_, "REFRESH" | "SETFOCUS" | "CLS" | "PRINTFORM") => Some((0, 0)),
|
|
(_, "DRAG") => Some((1, 1)),
|
|
(_, "MOVE") => Some((2, 4)),
|
|
(ObjectClass::ListBox | ObjectClass::ComboBox, "ADDITEM") => Some((1, 2)),
|
|
(ObjectClass::ListBox | ObjectClass::ComboBox, "REMOVEITEM") => Some((1, 1)),
|
|
(ObjectClass::Form | ObjectClass::PictureBox, "PRINT") => Some((0, usize::MAX)),
|
|
(ObjectClass::Form | ObjectClass::PictureBox, "TEXTWIDTH" | "TEXTHEIGHT") => Some((1, 1)),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn method_return_type(class: ObjectClass, name: &str) -> Option<PropertyType> {
|
|
match (class, name) {
|
|
(ObjectClass::Form | ObjectClass::PictureBox, "TEXTWIDTH" | "TEXTHEIGHT") => {
|
|
Some(PropertyType::Integer)
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn events(class: ObjectClass) -> &'static [&'static str] {
|
|
use ObjectClass::*;
|
|
match class {
|
|
Form => &[
|
|
"CLICK",
|
|
"DBLCLICK",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOAD",
|
|
"LOSTFOCUS",
|
|
"MOUSEDOWN",
|
|
"MOUSEMOVE",
|
|
"MOUSEUP",
|
|
"PAINT",
|
|
"RESIZE",
|
|
"UNLOAD",
|
|
],
|
|
CommandButton => &[
|
|
"CLICK",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOSTFOCUS",
|
|
],
|
|
TextBox => &[
|
|
"CHANGE",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOSTFOCUS",
|
|
],
|
|
ListBox => &[
|
|
"CLICK",
|
|
"DBLCLICK",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOSTFOCUS",
|
|
"MOUSEDOWN",
|
|
"MOUSEMOVE",
|
|
"MOUSEUP",
|
|
],
|
|
ComboBox => &[
|
|
"CHANGE",
|
|
"CLICK",
|
|
"DBLCLICK",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"DROPDOWN",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOSTFOCUS",
|
|
"MOUSEDOWN",
|
|
"MOUSEMOVE",
|
|
"MOUSEUP",
|
|
],
|
|
CheckBox => &[
|
|
"CLICK",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOSTFOCUS",
|
|
],
|
|
OptionButton => &[
|
|
"CLICK",
|
|
"DBLCLICK",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOSTFOCUS",
|
|
],
|
|
Frame => &["DRAGDROP", "DRAGOVER"],
|
|
Label => &[
|
|
"CHANGE",
|
|
"CLICK",
|
|
"DBLCLICK",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"MOUSEDOWN",
|
|
"MOUSEMOVE",
|
|
"MOUSEUP",
|
|
],
|
|
HScrollBar | VScrollBar => &[
|
|
"CHANGE",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOSTFOCUS",
|
|
],
|
|
Spin => &[
|
|
"CUSTOM",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOSTFOCUS",
|
|
],
|
|
PictureBox => &[
|
|
"CLICK",
|
|
"DBLCLICK",
|
|
"DRAGDROP",
|
|
"DRAGOVER",
|
|
"GOTFOCUS",
|
|
"KEYDOWN",
|
|
"KEYPRESS",
|
|
"KEYUP",
|
|
"LOSTFOCUS",
|
|
"MOUSEDOWN",
|
|
"MOUSEMOVE",
|
|
"MOUSEUP",
|
|
"PAINT",
|
|
],
|
|
Timer => &["TIMER"],
|
|
Menu => &["CLICK"],
|
|
DirListBox => &["CHANGE", "CLICK", "DBLCLICK", "PATHCHANGE"],
|
|
DriveListBox => &["CHANGE"],
|
|
FileListBox => &["CLICK", "DBLCLICK", "PATTERNCHANGE", "PATHCHANGE"],
|
|
Screen => &[],
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum EventParamType {
|
|
Integer,
|
|
Single,
|
|
Control,
|
|
}
|
|
|
|
pub fn event_params(event: &str) -> Option<&'static [(&'static str, EventParamType)]> {
|
|
use EventParamType::*;
|
|
Some(match event.to_ascii_uppercase().as_str() {
|
|
"KEYDOWN" | "KEYUP" => &[("KEYCODE", Integer), ("SHIFT", Integer)],
|
|
"KEYPRESS" => &[("KEYASCII", Integer)],
|
|
"MOUSEDOWN" | "MOUSEMOVE" | "MOUSEUP" => &[
|
|
("BUTTON", Integer),
|
|
("SHIFT", Integer),
|
|
("X", Single),
|
|
("Y", Single),
|
|
],
|
|
"DRAGDROP" => &[("SOURCE", Control), ("X", Single), ("Y", Single)],
|
|
"DRAGOVER" => &[
|
|
("SOURCE", Control),
|
|
("X", Single),
|
|
("Y", Single),
|
|
("STATE", Integer),
|
|
],
|
|
"UNLOAD" => &[("CANCEL", Integer)],
|
|
"CUSTOM" => &[("EVENTTYPE", Integer)],
|
|
"CLICK" | "DBLCLICK" | "CHANGE" | "DROPDOWN" | "GOTFOCUS" | "LOSTFOCUS" | "LOAD"
|
|
| "PAINT" | "RESIZE" | "TIMER" | "PATHCHANGE" | "PATTERNCHANGE" => &[],
|
|
_ => return None,
|
|
})
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct FormObject {
|
|
pub name: String,
|
|
pub class: ObjectClass,
|
|
pub parent_form: Option<String>,
|
|
pub array: bool,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct FormCatalog {
|
|
pub objects: Vec<FormObject>,
|
|
}
|
|
|
|
impl FormCatalog {
|
|
pub fn add(
|
|
&mut self,
|
|
name: impl Into<String>,
|
|
class: ObjectClass,
|
|
parent_form: Option<&str>,
|
|
array: bool,
|
|
) -> u16 {
|
|
let id = self.objects.len() as u16;
|
|
self.objects.push(FormObject {
|
|
name: name.into().to_uppercase(),
|
|
class,
|
|
parent_form: parent_form.map(str::to_uppercase),
|
|
array,
|
|
});
|
|
id
|
|
}
|
|
|
|
pub fn find(&self, name: &str) -> Option<(u16, &FormObject)> {
|
|
self.objects
|
|
.iter()
|
|
.enumerate()
|
|
.find(|(_, o)| o.name.eq_ignore_ascii_case(name))
|
|
.map(|(i, o)| (i as u16, o))
|
|
}
|
|
|
|
pub fn belongs_to(&self, object: &FormObject, form: &str) -> bool {
|
|
let mut parent = object.parent_form.as_deref();
|
|
for _ in 0..self.objects.len() {
|
|
let Some(name) = parent else { return false };
|
|
if name.eq_ignore_ascii_case(form) {
|
|
return true;
|
|
}
|
|
parent = self
|
|
.find(name)
|
|
.and_then(|(_, object)| object.parent_form.as_deref());
|
|
}
|
|
false
|
|
}
|
|
}
|