17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-05 06:24:27 +01:00

feat(editor): edit parameters of a placed include

This commit is contained in:
2026-10-03 00:37:17 +02:00
parent 968594c3e9
commit ced26d171f
16 changed files with 603 additions and 41 deletions

View File

@@ -210,8 +210,8 @@ void node_layers::visible(layer_handle Layer, bool const Visible)
}
if (Visible)
{
// nodes of a removed include stay out of sight
if (Node->m_layerhidden && (false == tracked(Node->m_instance) || false == instance(Node->m_instance).removed))
// nodes of a removed include stay out of sight, and so do the ones the editor replaced with its own
if (Node->m_layerhidden && (false == tracked(Node->m_instance) || (false == instance(Node->m_instance).removed && false == stale(Node))))
{
Node->visible(true);
Node->m_layerhidden = false;
@@ -613,7 +613,7 @@ bool node_layers::can_merge(layer_handle Source, layer_handle Target, std::strin
{
// directives of includes placed in the editor are prepared for the end of their layer file
auto const unsaved{std::any_of(std::begin(m_instances), std::end(m_instances), [&](include_instance const &Instance) {
return false == Instance.dead && false == Instance.removed && false == Instance.directive.empty() && resolve(Instance.layer) == Source;
return false == Instance.dead && false == Instance.removed && false == Instance.span.valid() && resolve(Instance.layer) == Source;
})};
if (unsaved)
{
@@ -695,6 +695,7 @@ void node_layers::instance_begin(std::string const &File, source_span const &Spa
included.layer = handle();
included.file = &(*m_templates.emplace(File).first);
included.span = Span;
included.context = m_context;
m_instance = static_cast<instance_handle>(m_instances.size());
}
@@ -741,7 +742,7 @@ void node_layers::removed(instance_handle Instance, bool Removed)
auto const includelayer{resolve(m_instances[Instance - 1].layer)};
auto const layervisible{false == valid(includelayer) || layer(includelayer).visible};
auto const update_node = [=, this](basic_node *Node, layer_item const Item) {
if (Node == nullptr || Node->m_instance != Instance)
if (Node == nullptr || Node->m_instance != Instance || (Item == layer_item::model && stale(Node)))
{
return;
}
@@ -791,6 +792,67 @@ instance_handle node_layers::place(layer_handle Layer, std::string const &File,
return static_cast<instance_handle>(m_instances.size());
}
// text of the directive of specified include, as changed in the editor or as it stands in the scenery file
std::string node_layers::directive(instance_handle const Instance) const
{
if (false == tracked(Instance))
{
return {};
}
auto const &included{instance(Instance)};
if (false == included.directive.empty() || false == included.span.valid() || false == valid(included.layer))
{
return included.directive;
}
std::string text(static_cast<std::size_t>(included.span.end - included.span.begin), '\0');
std::ifstream input{path(included.layer), std::ios_base::binary};
if (false == input.is_open() || false == input.seekg(included.span.begin).good() || false == input.read(text.data(), static_cast<std::streamsize>(text.size())).good())
{
return {};
}
return text;
}
// replaces the directive of specified include, the scenery file receives it on save
bool node_layers::modify(instance_handle const Instance, std::string const &Directive)
{
if (false == tracked(Instance) || m_instances[Instance - 1].dead || Directive.empty())
{
return false;
}
m_instances[Instance - 1].directive = Directive;
return true;
}
// takes the models specified include was loaded with out of the scene, once the editor shows its own in their place
void node_layers::rebuilt(instance_handle const Instance)
{
if (false == tracked(Instance) || m_instances[Instance - 1].rebuilt)
{
return;
}
auto const removed{m_instances[Instance - 1].removed};
for (auto *model : simulation::Instances.sequence())
{
if (model == nullptr || model->m_instance != Instance || model->m_preview)
{
continue;
}
// NOTE: the models themselves are left alone, events of the scenery can refer to them
simulation::Region->erase(model);
if (false == removed)
{
count(model->layer(), layer_item::model, -1);
}
if (model->visible())
{
model->visible(false);
model->m_layerhidden = true;
}
}
m_instances[Instance - 1].rebuilt = true;
}
} // namespace scene
//---------------------------------------------------------------------------

View File

@@ -100,10 +100,11 @@ struct include_instance
layer_handle layer{null_handle}; // layer of the file holding the directive
std::string const *file{nullptr}; // name of the included template
source_span span; // location of the whole directive in the file; invalid for directive which wasn't saved yet
std::string directive; // text of the directive, for include placed in the editor and not saved yet
layer_context context; // placement the directive of include placed in the editor was prepared for
std::string directive; // text of the directive, for include placed or changed in the editor and not saved yet
layer_context context; // placement in effect at the directive
bool removed{false}; // the include is to be dropped from the scenery
bool dead{false}; // removal of the include was saved
bool rebuilt{false}; // models the include was loaded with gave way to the ones made by the editor
};
// marks nodes defined by a template which was included in a way the editor doesn't keep track of
@@ -277,6 +278,18 @@ class node_layers
// registers include directive made in the editor, to be written to the file of specified layer on save.
// the directive has to be prepared for the placement in effect at the end of that file. returns: handle to the include
instance_handle place(layer_handle Layer, std::string const &File, std::string const &Directive);
// text of the directive of specified include, as changed in the editor or as it stands in the scenery file.
// returns: empty text if the directive can't be read
std::string directive(instance_handle Instance) const;
// replaces the directive of specified include, the scenery file receives it on save. NOTE: the nodes aren't touched
bool modify(instance_handle Instance, std::string const &Directive);
// takes the models specified include was loaded with out of the scene, once the editor shows its own in their place
void rebuilt(instance_handle Instance);
// true if specified node was replaced by the editor with a node showing the current state of its include
bool stale(basic_node const *Node) const
{
return tracked(Node->m_instance) && instance(Node->m_instance).rebuilt && false == Node->m_preview;
}
// true if specified layer is included, directly or not, by the other one
bool is_descendant(layer_handle Layer, layer_handle const Ancestor) const;

View File

@@ -275,6 +275,7 @@ struct node_layers::file_patch
std::size_t length{0}; // size of that definition
basic_node const *node{nullptr}; // node defined by the replacement
layer_handle site{null_handle}; // layer included by the directive in the replacement
instance_handle instance{0}; // include of a template made by the directive in the replacement
layer_handle inlined{null_handle}; // layer whose content replaces the range
};
std::vector<edit> edits;
@@ -460,6 +461,10 @@ bool node_layers::compose(save_state &State, layer_handle const Layer, compositi
{
Output.sites.push_back({edit.site, span});
}
if (edit.instance != 0)
{
Output.instances.push_back({edit.instance, span});
}
Output.text.append(edit.text, edit.lead - lead, std::string::npos);
}
cursor = end;
@@ -692,6 +697,17 @@ save_result node_layers::save(std::vector<std::string> const &Rootstatements)
edit.end = included.span.end;
state.patches[included.layer].edits.emplace_back(std::move(edit));
}
else if (false == included.directive.empty())
{
// changed in the editor, the new directive takes the place of the one in the file
file_patch::edit edit;
edit.begin = included.span.begin;
edit.end = included.span.end;
edit.length = included.directive.size();
edit.text = included.directive;
edit.instance = static_cast<instance_handle>(idx + 1);
state.patches[included.layer].edits.emplace_back(std::move(edit));
}
}
else if (false == included.removed && false == included.directive.empty())
{
@@ -840,7 +856,7 @@ save_result node_layers::save(std::vector<std::string> const &Rootstatements)
for (std::size_t idx = 0; idx < m_instances.size(); ++idx)
{
auto const &included{m_instances[idx]};
if (false == included.dead && false == included.removed && included.span.valid() && state.content.count(included.layer) != 0)
if (false == included.dead && false == included.removed && included.directive.empty() && included.span.valid() && state.content.count(included.layer) != 0)
{
state.instances[included.layer].emplace_back(static_cast<instance_handle>(idx + 1));
}

View File

@@ -385,6 +385,7 @@ public:
std::string m_name;
bool m_dirty { false };
bool m_layerhidden { false }; // the node was visible until the editor hid its scenery layer, or the include which defines it
bool m_preview { false }; // the node was made by the editor to show an include it placed or changed, and is replaced when the include changes
scene::layer_handle m_layer { null_handle }; // scenery layer this node belongs to, if any
// include of an *.inc template which defines the node; 0 if the node is defined directly by a scenery layer file.
// such nodes can't be rewritten one by one on scenery save. set only for scenery opened for editing