Projektmodule und vollständiges TBC-Kompilat umsetzen und Change archivieren
This commit is contained in:
@@ -252,12 +252,7 @@ impl FormsModel {
|
||||
return Ok(PropertyValue::Integer(value.saturating_sub(2)));
|
||||
}
|
||||
if spec.name == "PARENT" {
|
||||
let parent = obj.description.parent_form.as_deref().and_then(|name| {
|
||||
self.objects
|
||||
.iter()
|
||||
.position(|candidate| candidate.description.name.eq_ignore_ascii_case(name))
|
||||
.map(|id| (id as u16, None))
|
||||
});
|
||||
let parent = obj.description.parent.map(|id| (id, None));
|
||||
return Ok(PropertyValue::Object(parent));
|
||||
}
|
||||
Ok(obj.properties[property as usize].clone())
|
||||
@@ -834,12 +829,7 @@ impl FormsModel {
|
||||
if obj.description.class == ObjectClass::Form {
|
||||
return Some(current);
|
||||
}
|
||||
let parent = obj.description.parent_form.as_deref()?;
|
||||
current = self
|
||||
.objects
|
||||
.iter()
|
||||
.position(|candidate| candidate.description.name.eq_ignore_ascii_case(parent))?
|
||||
as u16;
|
||||
current = obj.description.parent?;
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -959,7 +949,7 @@ impl FormsModel {
|
||||
}
|
||||
|
||||
fn select_option(&mut self, key: ObjectKey) -> Result<(), RuntimeError> {
|
||||
let parent = self.instance(key)?.description.parent_form.clone();
|
||||
let parent = self.instance(key)?.description.parent;
|
||||
let value_id = forms::property(ObjectClass::OptionButton, "VALUE")
|
||||
.unwrap()
|
||||
.0 as usize;
|
||||
@@ -969,7 +959,7 @@ impl FormsModel {
|
||||
}
|
||||
let same_group = self.instance(other).is_ok_and(|obj| {
|
||||
obj.description.class == ObjectClass::OptionButton
|
||||
&& obj.description.parent_form == parent
|
||||
&& obj.description.parent == parent
|
||||
});
|
||||
if same_group {
|
||||
self.instance_mut(other)?.properties[value_id] = PropertyValue::Integer(0);
|
||||
@@ -1006,12 +996,8 @@ impl FormsModel {
|
||||
&& self
|
||||
.instance(key)
|
||||
.ok()
|
||||
.and_then(|obj| obj.description.parent_form.as_deref())
|
||||
.and_then(|parent| {
|
||||
self.objects
|
||||
.iter()
|
||||
.find(|obj| obj.description.name.eq_ignore_ascii_case(parent))
|
||||
})
|
||||
.and_then(|obj| obj.description.parent)
|
||||
.and_then(|parent| self.objects.get(parent as usize))
|
||||
.is_some_and(|parent| parent.description.class == ObjectClass::Form);
|
||||
if invalid || title_shortcut {
|
||||
Err(RuntimeError::ILLEGAL_FUNCTION_CALL)
|
||||
@@ -1325,19 +1311,12 @@ impl FormsModel {
|
||||
}
|
||||
|
||||
fn menu_children(&self, parent: ObjectKey) -> Vec<ObjectKey> {
|
||||
let Ok(parent) = self.instance(parent) else {
|
||||
return Vec::new();
|
||||
};
|
||||
self.keys()
|
||||
.into_iter()
|
||||
.filter(|key| {
|
||||
self.instance(*key).is_ok_and(|object| {
|
||||
object.description.class == ObjectClass::Menu
|
||||
&& object
|
||||
.description
|
||||
.parent_form
|
||||
.as_deref()
|
||||
.is_some_and(|name| name.eq_ignore_ascii_case(&parent.description.name))
|
||||
&& object.description.parent == Some(parent.0)
|
||||
}) && self.boolean(*key, "VISIBLE")
|
||||
})
|
||||
.collect()
|
||||
@@ -1385,23 +1364,15 @@ impl FormsModel {
|
||||
}
|
||||
if shift & umschalt::ALT != 0 {
|
||||
if let Some(ch) = key.chars().next().map(|ch| ch.to_ascii_uppercase()) {
|
||||
if let Some(target) =
|
||||
self.form_controls(form).into_iter().find(|candidate| {
|
||||
Self::access_key(&self.string(*candidate, "CAPTION")) == Some(ch)
|
||||
&& self.boolean(*candidate, "ENABLED")
|
||||
&& self.boolean(*candidate, "VISIBLE")
|
||||
&& self.instance(*candidate).is_ok_and(|obj| {
|
||||
obj.description.class != ObjectClass::Menu
|
||||
|| obj.description.parent_form.as_deref().is_some_and(
|
||||
|parent| {
|
||||
parent.eq_ignore_ascii_case(
|
||||
&self.objects[form as usize].description.name,
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
{
|
||||
if let Some(target) = self.form_controls(form).into_iter().find(|candidate| {
|
||||
Self::access_key(&self.string(*candidate, "CAPTION")) == Some(ch)
|
||||
&& self.boolean(*candidate, "ENABLED")
|
||||
&& self.boolean(*candidate, "VISIBLE")
|
||||
&& self.instance(*candidate).is_ok_and(|obj| {
|
||||
obj.description.class != ObjectClass::Menu
|
||||
|| obj.description.parent == Some(form)
|
||||
})
|
||||
}) {
|
||||
if self
|
||||
.instance(target)
|
||||
.is_ok_and(|obj| obj.description.class == ObjectClass::Menu)
|
||||
@@ -1580,21 +1551,14 @@ impl FormsModel {
|
||||
let mut top = self.integer(key, "TOP").unwrap_or(0).max(0) as usize + 1;
|
||||
let width = self.integer(key, "WIDTH").unwrap_or(1).max(1) as usize;
|
||||
let height = self.integer(key, "HEIGHT").unwrap_or(1).max(1) as usize;
|
||||
let mut parent = obj.description.parent_form.as_deref();
|
||||
let mut parent = obj.description.parent;
|
||||
for _ in 0..self.objects.len() {
|
||||
let Some(name) = parent else { break };
|
||||
let Some((id, parent_obj)) = self
|
||||
.objects
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, candidate)| candidate.description.name.eq_ignore_ascii_case(name))
|
||||
else {
|
||||
break;
|
||||
};
|
||||
let parent_key = (id as u16, None);
|
||||
let Some(id) = parent else { break };
|
||||
let parent_obj = self.objects.get(id as usize)?;
|
||||
let parent_key = (id, None);
|
||||
left += self.integer(parent_key, "LEFT").unwrap_or(0).max(0) as usize;
|
||||
top += self.integer(parent_key, "TOP").unwrap_or(0).max(0) as usize;
|
||||
parent = parent_obj.description.parent_form.as_deref();
|
||||
parent = parent_obj.description.parent;
|
||||
}
|
||||
Some((left, top, width, height))
|
||||
}
|
||||
@@ -2357,12 +2321,7 @@ impl FormsModel {
|
||||
&& self
|
||||
.instance(key)
|
||||
.ok()
|
||||
.and_then(|obj| obj.description.parent_form.as_deref())
|
||||
.is_some_and(|parent| {
|
||||
parent.eq_ignore_ascii_case(
|
||||
&self.objects[form as usize].description.name,
|
||||
)
|
||||
})
|
||||
.is_some_and(|obj| obj.description.parent == Some(form))
|
||||
{
|
||||
if self.boolean(key, "VISIBLE") {
|
||||
let caption = format!(" {} ", self.caption(key));
|
||||
@@ -2419,20 +2378,12 @@ impl FormsModel {
|
||||
.is_some_and(|root| self.root_form(*root) == Some(form))
|
||||
{
|
||||
let mut popup_left = left + 1;
|
||||
for root in
|
||||
self.form_controls(form).into_iter().filter(|key| {
|
||||
self.instance(*key).is_ok_and(|object| {
|
||||
object.description.class == ObjectClass::Menu
|
||||
&& object.description.parent_form.as_deref().is_some_and(
|
||||
|parent| {
|
||||
parent.eq_ignore_ascii_case(
|
||||
&self.objects[form as usize].description.name,
|
||||
)
|
||||
},
|
||||
)
|
||||
}) && self.boolean(*key, "VISIBLE")
|
||||
})
|
||||
{
|
||||
for root in self.form_controls(form).into_iter().filter(|key| {
|
||||
self.instance(*key).is_ok_and(|object| {
|
||||
object.description.class == ObjectClass::Menu
|
||||
&& object.description.parent == Some(form)
|
||||
}) && self.boolean(*key, "VISIBLE")
|
||||
}) {
|
||||
if Some(&root) == self.menu_path.first() {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -56,9 +56,7 @@ impl FormFile {
|
||||
} else {
|
||||
let array = forms::property(node.class, "INDEX")
|
||||
.and_then(|(property, _)| node.properties.get(&property))
|
||||
.is_some_and(
|
||||
|value| matches!(value, PropertyValue::Integer(index) if *index != 0),
|
||||
);
|
||||
.is_some();
|
||||
catalog.add(&node.name, node.class, parent, array);
|
||||
}
|
||||
for child in &node.children {
|
||||
@@ -70,44 +68,99 @@ impl FormFile {
|
||||
catalog
|
||||
}
|
||||
|
||||
pub fn apply(&self, model: &mut FormsModel) -> Result<(), tb_runtime::errors::RuntimeError> {
|
||||
fn apply_node(
|
||||
pub fn code_line(&self) -> u32 {
|
||||
self.original.as_ref().map_or(1, |original| {
|
||||
original.bytes[..original.bytes.len() - original.code.len()]
|
||||
.bytes()
|
||||
.filter(|b| *b == b'\n')
|
||||
.count() as u32
|
||||
+ 1
|
||||
})
|
||||
}
|
||||
|
||||
pub fn initial_values(
|
||||
&self,
|
||||
catalog: &FormCatalog,
|
||||
) -> Result<Vec<FormInitial>, tb_runtime::errors::RuntimeError> {
|
||||
fn collect(
|
||||
node: &FormNode,
|
||||
model: &mut FormsModel,
|
||||
menu_depth: usize,
|
||||
parent: Option<u16>,
|
||||
catalog: &FormCatalog,
|
||||
out: &mut Vec<FormInitial>,
|
||||
depth: usize,
|
||||
) -> Result<(), tb_runtime::errors::RuntimeError> {
|
||||
let menu_depth = if node.class == ObjectClass::Menu {
|
||||
menu_depth + 1
|
||||
} else {
|
||||
menu_depth
|
||||
};
|
||||
if menu_depth > 6 {
|
||||
return Err(tb_runtime::errors::RuntimeError::ILLEGAL_FUNCTION_CALL);
|
||||
let depth = depth + usize::from(node.class == ObjectClass::Menu);
|
||||
if depth > 6 {
|
||||
return Err(tb_runtime::errors::RuntimeError(5));
|
||||
}
|
||||
let object = model
|
||||
let object = catalog
|
||||
.objects
|
||||
.iter()
|
||||
.position(|candidate| candidate.description.name.eq_ignore_ascii_case(&node.name))
|
||||
.position(|o| {
|
||||
o.name.eq_ignore_ascii_case(&node.name)
|
||||
&& o.parent == parent
|
||||
&& o.class == node.class
|
||||
})
|
||||
.ok_or(tb_runtime::errors::RuntimeError(420))? as u16;
|
||||
let index = forms::property(node.class, "INDEX")
|
||||
.and_then(|(property, _)| node.properties.get(&property))
|
||||
.and_then(|value| match value {
|
||||
PropertyValue::Integer(value) => Some(*value),
|
||||
_ => None,
|
||||
.and_then(|(id, _)| node.properties.get(&id))
|
||||
.and_then(|v| {
|
||||
if let PropertyValue::Integer(n) = v {
|
||||
Some(*n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or(0);
|
||||
if index != 0 && !model.is_loaded_at(object, Some(index)) {
|
||||
model.load_design_array(object, index)?;
|
||||
}
|
||||
for (property, value) in &node.properties {
|
||||
model.set_initial_at(object, Some(index), *property, value.clone())?;
|
||||
if out.iter().any(|v| v.object == object && v.index == index) {
|
||||
return Err(tb_runtime::errors::RuntimeError(5));
|
||||
}
|
||||
out.push(FormInitial {
|
||||
object,
|
||||
index,
|
||||
properties: node.properties.clone(),
|
||||
});
|
||||
for child in &node.children {
|
||||
apply_node(child, model, menu_depth)?;
|
||||
collect(child, Some(object), catalog, out, depth)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
apply_node(&self.root, model, 0)
|
||||
let mut values = Vec::new();
|
||||
collect(&self.root, None, catalog, &mut values, 0)?;
|
||||
Ok(values)
|
||||
}
|
||||
|
||||
pub fn apply(&self, model: &mut FormsModel) -> Result<(), tb_runtime::errors::RuntimeError> {
|
||||
let catalog = FormCatalog {
|
||||
objects: model
|
||||
.objects
|
||||
.iter()
|
||||
.map(|o| o.description.clone())
|
||||
.collect(),
|
||||
};
|
||||
for initial in self.initial_values(&catalog)? {
|
||||
initial.apply(model)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct FormInitial {
|
||||
pub object: u16,
|
||||
pub index: i32,
|
||||
pub properties: BTreeMap<u16, PropertyValue>,
|
||||
}
|
||||
|
||||
impl FormInitial {
|
||||
pub fn apply(&self, model: &mut FormsModel) -> Result<(), tb_runtime::errors::RuntimeError> {
|
||||
if self.index != 0 && !model.is_loaded_at(self.object, Some(self.index)) {
|
||||
model.load_design_array(self.object, self.index)?;
|
||||
}
|
||||
for (property, value) in &self.properties {
|
||||
model.set_initial_at(self.object, Some(self.index), *property, value.clone())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user