19 #include <wx/dcclient.h>
20 #include <wx/dirdlg.h>
21 #include <wx/graphics.h>
23 #include <wx/msgdlg.h>
24 #include <wx/richtooltip.h>
25 #include <wx/settings.h>
27 #include <wx/stattext.h>
28 #include <wx/treectrl.h>
30 #include <wx/propgrid/propgrid.h>
31 #include <wx/propgrid/props.h>
33 #include <wx/propgrid/advprops.h>
35 #include <wx/aui/framemanager.h>
47 #ifdef SPH_USE_CHAISCRIPT
48 static ChaiScriptJob scriptDummy(
"dummy");
57 , callbacks(callbacks) {
75 const std::string fixedName = nameMgr.
getName(currentName);
76 if (fixedName != currentName) {
78 settings.
set(
"name", fixedName);
88 const wxSize size = editor->GetSize();
102 const wxSize size = editor->GetSize();
115 clonedTree.
push(node);
119 for (
Size i = 0; i < origTree.
size(); ++i) {
120 nodes[clonedTree[i]].position = nodes[origTree[i]].position + offset;
128 depthMap.
insert(node, depth);
134 depthChanged =
false;
135 for (
auto& element : depthMap) {
147 }
while (depthChanged);
151 for (
auto& element : depthMap) {
152 const int depth = element.value;
154 depthMapInv.
insert(depth, {});
156 depthMapInv[depth].push(element.key);
159 for (
auto& element : depthMapInv) {
160 const int depth = element.key;
162 for (
auto& node : element.value) {
203 for (
auto& element :
reverse(nodes)) {
206 if (rect.Contains(wxPoint(
position))) {
214 for (
auto& element : nodes) {
229 return {
nullptr, 0 };
248 out.
set<
bool>(name, entry.
get());
251 out.
set<
int>(name, entry.
get());
263 out.
set<std::string>(name, entry.
get());
294 for (
auto& element : nodes) {
296 const VisNode vis = element.value;
300 out->set(
"class_name", node->
className());
307 out->set(slot.
name, provider->instanceName());
318 wxMessageBox(std::string(
"Cannot save file.\n\n") + e.
what(),
"Error", wxOK);
338 entry.
set(input.
get<
bool>(name));
341 entry.
set(input.
get<
int>(name));
353 entry.
set(input.
get<std::string>(name));
377 std::cout <<
"Failed to load value, keeping the default.\n" << e.
what() << std::endl;
395 inNodes->enumerateChildren([
this, &allToConnect](std::string name,
ConfigNode& input) {
398 const std::string className = input.
get<std::string>(
"class_name");
401 throw Exception(
"cannot find desc for node '" + className +
"'");
404 wxMessageBox(e.
what(),
"Error", wxOK);
414 const std::string slotName = node->
getSlot(i).
name;
422 for (
auto& toConnect : allToConnect) {
423 for (
auto& element : nodes) {
424 if (element.key->instanceName() == toConnect.get<2>()) {
425 element.key->connect(toConnect.get<0>(), toConnect.get<1>());
431 for (
auto& pair : nodes) {
432 nodeList.
push(pair.key);
434 batch.
load(config, nodeList);
437 wxMessageBox(std::string(
"Cannot load file.\n\n") + e.
what(),
"Error", wxOK);
462 for (
Size i = 0; i < runCnt; ++i) {
484 wxMessageBox(std::string(
485 "Incomplete set up of batch run.\nSet up all parameters in Project / Batch Run."));
495 batchNodes.
push(runNode);
498 wxMessageBox(std::string(
"Cannot start batch run.\n\n") + e.
what(),
"Error", wxOK);
502 for (
Size i = 0; i < batchNodes.
size(); ++i) {
503 batchNodes[i]->connect(
root,
"job " + std::to_string(i));
510 #ifdef SPH_USE_CHAISCRIPT
513 for (
const auto& node : rootNodes) {
519 callbacks->
startRun(node, globals,
"Script '" + file.
native() +
"'");
521 throw InvalidSetup(
"Cannot start script '" + file.
native() +
"', no ChaiScript support.");
527 for (
auto& element : nodes) {
534 if (inputs.
empty()) {
535 wxMessageBox(
"No simulations to start.");
540 for (
Size i = 0; i < inputs.
size(); ++i) {
541 inputs[i]->connect(
root,
"job " + std::to_string(i));
549 for (
auto& element : nodes) {
589 for (
auto& element : nodes) {
590 names.
push(element.key->instanceName());
599 for (
auto& pair : nodes) {
600 nodeList.
push(pair.key);
603 if (batchDialog->ShowModal() == wxID_OK) {
607 batchDialog->Destroy();
611 return alignedNew<RenderPane>(parent, wxDefaultSize, node.
sharedFromThis(), globals);
622 if (nodeList.
empty()) {
623 wxMessageBox(std::string(
"No simulation nodes added. First, create a simulation by double-clicking "
624 "an item in the node list on the right side."),
630 if (nodeList.
size() == 1) {
638 if (dialog->ShowModal() == wxID_OK) {
653 : wxPanel(parent, wxID_ANY)
654 , callbacks(callbacks)
655 , nodeWindow(parent) {
656 this->SetMinSize(wxSize(1024, 768));
658 this->Connect(wxEVT_PAINT, wxPaintEventHandler(NodeEditor::onPaint));
659 this->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler(NodeEditor::onMouseWheel));
660 this->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(NodeEditor::onLeftDown));
661 this->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(NodeEditor::onLeftUp));
662 this->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(NodeEditor::onRightUp));
663 this->Connect(wxEVT_MOTION, wxMouseEventHandler(NodeEditor::onMouseMotion));
664 this->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(NodeEditor::onDoubleClick));
667 static void drawCenteredText(wxGraphicsContext* gc,
668 const std::string& text,
671 wxDouble width, height, descent, externalLeading;
672 gc->GetTextExtent(text, &width, &height, &descent, &externalLeading);
673 const Pixel pivot = (from + to) / 2 -
Pixel(
int(width), int(height)) / 2;
674 gc->DrawText(text, pivot.
x, pivot.
y);
686 static wxColour getLineColor(
const Rgba& background) {
689 return wxColour(30, 30, 30);
692 return wxColour(230, 230, 230);
699 storagePen.SetColour(wxColour(230, 230, 230));
702 materialPen.SetColour(wxColour(255, 120, 60));
703 materialPen.SetStyle(wxPENSTYLE_SHORT_DASH);
706 geometryPen.SetColour(wxColour(60, 120, 255));
707 geometryPen.SetStyle(wxPENSTYLE_SHORT_DASH);
710 cameraPen.SetColour(wxColour(150, 225, 100));
711 cameraPen.SetStyle(wxPENSTYLE_SHORT_DASH);
718 storagePen.SetColour(wxColour(30, 30, 30));
721 materialPen.SetColour(wxColour(150, 40, 10));
722 materialPen.SetStyle(wxPENSTYLE_SHORT_DASH);
725 geometryPen.SetColour(wxColour(0, 20, 80));
726 geometryPen.SetStyle(wxPENSTYLE_SHORT_DASH);
729 cameraPen.SetColour(wxColour(80, 10, 10));
730 cameraPen.SetStyle(wxPENSTYLE_SHORT_DASH);
734 static wxPen& getNodePen(
const ExtJobType type,
const bool isLightTheme) {
736 return NODE_PENS_LIGHT[type];
738 return NODE_PENS_DARK[type];
742 static Rgba decreaseContrast(
const Rgba& color,
const float amount,
const bool darken) {
744 return color.
darken(amount);
746 return color.
brighten(3.f * amount);
750 static void drawCurve(wxGraphicsContext* gc,
const Pixel from,
const Pixel to) {
751 wxGraphicsPath path = gc->CreatePath();
752 path.MoveToPoint(from.
x, from.
y);
754 const Pixel dp = to - from;
755 path.AddCurveToPoint(from.x + dp.
x / 2, from.y, from.x + dp.
x / 2, to.
y, to.
x, to.
y);
757 gc->StrokePath(path);
775 return fromSlot.
used && provided && provided.
value() == fromSlot.
type;
780 return toSlot.
used && provided && provided.
value() == toSlot.
type;
784 wxColour NodeEditor::getSlotColor(
const NodeSlot& slot,
const Rgba& background) {
785 if (!state.mousePosition) {
787 return wxColour(background);
792 if (state.connectingSlot == slot) {
794 return wxColour(0, 220, 0);
797 return wxColour(background);
798 }
else if (state.connectingSlot && !canConnectSlots(state.connectingSlot.value(), slot)) {
800 return wxColour(200, 0, 0);
803 return wxColour(0, 220, 0);
807 void NodeEditor::paintNode(wxGraphicsContext* gc,
const Rgba& background,
const VisNode& vis) {
812 const bool isLightTheme = background.
intensity() > 0.5f;
814 wxBrush brush = *wxBLACK_BRUSH;
817 brushColor = decreaseContrast(background, 0.1f, isLightTheme);
819 brushColor = background.
blend(
Rgba(pen.GetColour()), 0.2f);
821 brush.SetColour(wxColour(brushColor));
825 const wxFont font = wxSystemSettings::GetFont(wxSYS_SYSTEM_FONT);
826 const Rgba lineColor(getLineColor(background));
827 gc->SetFont(font, wxColour(lineColor));
829 if (&vis == state.activated) {
841 wxColour disabledTextColor(decreaseContrast(lineColor, 0.3f, !isLightTheme));
842 gc->SetFont(font.Smaller(), disabledTextColor);
847 gc->SetFont(font, wxColour(lineColor));
852 pen.SetColour(isLightTheme ? wxColour(160, 160, 160) : wxColour(20, 20, 20));
854 const int lineY = 44;
855 const int padding = (&vis == state.activated) ? 2 : 1;
858 pen.SetColour(isLightTheme ? wxColour(240, 240, 240) : wxColour(100, 100, 100));
860 gc->StrokeLine(
position.x + padding,
871 brush.SetColour(this->getSlotColor(
NodeSlot{ &vis, i }, background));
874 pen = getNodePen(slot.
type, isLightTheme);
875 pen.SetStyle(wxPENSTYLE_SOLID);
881 gc->SetFont(font, wxColour(lineColor));
883 gc->SetFont(font, disabledTextColor);
885 gc->DrawText(slot.
name, p1.
x + 14, p1.
y - 10);
894 pen = getNodePen(provided.
value(), isLightTheme);
895 pen.SetStyle(wxPENSTYLE_SOLID);
905 out->set(
"offset", state.offset);
906 out->set(
"zoom", state.zoom);
911 state.offset = in->
get<
Pixel>(
"offset");
912 state.zoom = in->
get<
float>(
"zoom");
915 void NodeEditor::paintCurves(wxGraphicsContext* gc,
const Rgba& background,
const VisNode& vis) {
918 wxPen pen = *wxBLACK_PEN;
920 pen.SetColour(getLineColor(background));
923 if (state.mousePosition && state.connectingSlot && state.connectingSlot->vis ==
addressOf(vis)) {
925 const Pixel sourcePoint = state.connectingSlot->position();
937 drawCurve(gc, p1, p2);
942 void NodeEditor::onPaint(wxPaintEvent&
UNUSED(evt)) {
946 wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
951 const wxGraphicsMatrix matrix =
952 gc->CreateMatrix(state.zoom, 0.f, 0.f, state.zoom, state.offset.x, state.offset.y);
953 gc->SetTransform(matrix);
957 const Rgba background(dc.GetBackground().GetColour());
960 for (
auto& element : nodes) {
961 this->paintCurves(gc, background, element.value);
965 for (
auto& element : nodes) {
966 this->paintNode(gc, background, element.value);
972 void NodeEditor::onMouseMotion(wxMouseEvent& evt) {
974 if (evt.Dragging()) {
975 if (!state.mousePosition) {
981 if (state.selected) {
983 state.selected->position += (
mousePosition - state.mousePosition.value()) / state.zoom;
984 }
else if (!state.connectingSlot) {
992 if (slot != state.lastSlot) {
993 state.lastSlot = slot;
1001 void NodeEditor::onMouseWheel(wxMouseEvent& evt) {
1002 constexpr
float MAX_ZOOM_OUT = 0.2f;
1003 constexpr
float MAX_ZOOM_IN = 4.f;
1006 const float spin = evt.GetWheelRotation();
1007 const float amount = (spin > 0.f) ? 1.2f : 1.f / 1.2f;
1008 state.zoom =
clamp(state.zoom * amount, MAX_ZOOM_OUT, MAX_ZOOM_IN);
1009 if (state.zoom != MAX_ZOOM_OUT && state.zoom != MAX_ZOOM_IN) {
1010 state.offset += (
position - state.offset) * (1.f - amount);
1016 void NodeEditor::onLeftDown(wxMouseEvent& evt) {
1021 if (slot.
vis !=
nullptr) {
1022 state.connectingSlot = slot;
1036 void NodeEditor::onLeftUp(wxMouseEvent& evt) {
1038 state.selected =
nullptr;
1040 if (!state.connectingSlot) {
1043 NodeSlot sourceSlot = state.connectingSlot.value();
1048 if (targetSlot.
vis !=
nullptr && canConnectSlots(sourceSlot, targetSlot)) {
1068 state.connectingSlot =
NOTHING;
1072 void NodeEditor::onRightUp(wxMouseEvent& evt) {
1077 if (vis !=
nullptr) {
1080 menu.Append(0,
"Evaluate");
1081 menu.Append(1,
"Render preview");
1085 menu.Append(2,
"Evaluate all");
1087 if (vis !=
nullptr) {
1088 menu.Append(3,
"Clone");
1089 menu.Append(4,
"Clone tree");
1090 menu.Append(5,
"Layout");
1091 menu.Append(6,
"Delete");
1092 menu.Append(7,
"Delete tree");
1094 menu.Append(8,
"Delete all");
1096 menu.Bind(wxEVT_COMMAND_MENU_SELECTED, [
this, vis](wxCommandEvent& evt) {
1097 const Size index = evt.GetId();
1102 }
catch (
const std::exception& e) {
1103 wxMessageBox(std::string(
"Cannot run the node: ") + e.what(),
"Error", wxOK);
1110 wxMessageBox(std::string(
"Cannot start render preview: ") + e.
what(),
"Error", wxOK);
1141 this->PopupMenu(&menu);
1144 void NodeEditor::onDoubleClick(wxMouseEvent& evt) {
1148 state.activated = vis;
1162 wxDirDialog dialog(
nullptr,
"Choose directory",
"", wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
1163 if (dialog.ShowModal() == wxID_OK) {
1164 wxString path = dialog.GetPath();
1165 property->SetValue(path);
1166 this->SetValue(path);
1180 : formats(
std::move(formats)) {}
1185 property->SetValue(file->native());
1186 this->SetValue(file->native());
1201 : formats(
std::move(formats)) {}
1206 property->SetValue(file->native());
1207 this->SetValue(file->native());
1216 Function<wxPGEditorDialogAdapter*()> makeAdapter;
1219 using wxFileProperty::wxFileProperty;
1226 return makeAdapter();
1232 class ComponentProperty :
public wxFloatProperty {
1238 : wxFloatProperty(name, wxPG_LABEL, value[index])
1241 virtual void OnSetValue()
override {
1242 wxFloatProperty::OnSetValue();
1252 : wxStringProperty(name, wxPG_LABEL,
"")
1254 this->SetFlagRecursively(wxPG_PROP_READONLY,
true);
1257 for (
Size i = 0; i < 3; ++i) {
1258 components[i] =
new ComponentProperty(
this, labels[i], value, i);
1259 this->AppendChild(components[i]);
1267 for (
Size i = 0; i < 3; ++i) {
1268 v[i] = components[i]->GetValue();
1275 for (
Size i = 0; i < 3; ++i) {
1276 value += components[i]->GetValue().GetString() +
", ";
1278 value.RemoveLast(2);
1280 this->SetValue(value);
1284 wxPropertyGridEvent evt(wxEVT_PG_CHANGED);
1285 evt.SetProperty(
this);
1286 parent->GetEventHandler()->ProcessEvent(evt);
1293 class ComponentProperty :
public wxFloatProperty {
1299 : wxFloatProperty(name, wxPG_LABEL, value)
1302 virtual void OnSetValue()
override {
1303 wxFloatProperty::OnSetValue();
1313 : wxStringProperty(name, wxPG_LABEL,
"")
1315 this->SetFlagRecursively(wxPG_PROP_READONLY,
true);
1317 components[0] =
new ComponentProperty(
this,
"from", value.
lower());
1318 components[1] =
new ComponentProperty(
this,
"to", value.
upper());
1319 for (ComponentProperty* comp : components) {
1320 this->AppendChild(comp);
1327 return Interval(components[0]->GetValue(), components[1]->GetValue());
1331 wxString value =
"[ " + components[0]->GetValue().GetString() +
", " +
1332 components[1]->GetValue().GetString() +
" ]";
1333 this->SetValue(value);
1337 wxPropertyGridEvent evt(wxEVT_PG_CHANGED);
1338 evt.SetProperty(
this);
1339 parent->GetEventHandler()->ProcessEvent(evt);
1346 wxPropertyGrid* grid;
1353 return grid->Append(
new wxPropertyCategory(name));
1356 wxPGProperty*
addBool(
const std::string& name,
const bool value)
const {
1357 return grid->Append(
new wxBoolProperty(name, wxPG_LABEL, value));
1360 wxPGProperty*
addInt(
const std::string& name,
const int value)
const {
1361 return grid->Append(
new wxIntProperty(name, wxPG_LABEL, value));
1365 return grid->Append(
new wxFloatProperty(name, wxPG_LABEL, value));
1369 wxPGProperty* prop = grid->Append(
new VectorProperty(grid, name, value));
1370 grid->Collapse(prop);
1375 wxPGProperty* prop = grid->Append(
new IntervalProperty(grid, name, value));
1376 grid->Collapse(prop);
1380 wxPGProperty*
addString(
const std::string& name,
const std::string& value)
const {
1381 return grid->Append(
new wxStringProperty(name, wxPG_LABEL, value));
1390 prop->
setFunc([type, formats = std::move(formats)]() -> wxPGEditorDialogAdapter* {
1400 return grid->Append(prop);
1404 return addEnum<wxEnumProperty>(name, entry);
1408 return addEnum<wxFlagsProperty>(name, entry);
1414 return grid->Append(
new CurveProperty(name, entry->getCurve()));
1417 void setTooltip(wxPGProperty* prop,
const std::string& tooltip)
const {
1418 grid->SetPropertyHelpString(prop, tooltip);
1422 template <
typename TProperty>
1424 wxArrayString values;
1434 flags.Add(option.value);
1436 return grid->Append(
new TProperty(name, wxPG_LABEL, values, flags, wrapper.
value));
1450 , propertyEntryMap(propertyEntryMapping) {}
1452 virtual void onCategory(
const std::string& name)
const override {
1457 wxPGProperty* prop =
nullptr;
1458 const std::string name = entry.
getName();
1464 prop = wrapper.
addInt(name, entry.
get());
1482 prop = wrapper.
addPath(name, entry.
get(), type.
value(), std::move(formats));
1486 prop = wrapper.
addEnum(name, entry);
1489 prop = wrapper.
addFlags(name, entry);
1498 const std::string tooltip = entry.
getTooltip();
1499 if (!tooltip.empty()) {
1503 propertyEntryMap.
insert(prop, &entry);
1505 SPH_ASSERT(propertyEntryMap[prop]->enabled() ||
1512 : wxPanel(parent, wxID_ANY) {
1513 aui = makeAuto<wxAuiManager>(
this);
1515 nodeEditor =
new NodeEditor(
this, callbacks);
1516 nodeMgr = makeShared<NodeManager>(nodeEditor, callbacks);
1519 grid =
new wxPropertyGrid(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE);
1520 grid->SetExtraStyle(wxPG_EX_HELP_AS_TOOLTIPS);
1521 grid->SetMinSize(wxSize(300, -1));
1523 grid->Bind(wxEVT_PG_CHANGED, [
this, callbacks](wxPropertyGridEvent& evt) {
1524 wxPGProperty* prop = evt.GetProperty();
1525 if (!propertyEntryMap.
contains(prop)) {
1532 wxVariant value = prop->GetValue();
1535 case IVirtualEntry::Type::BOOL:
1536 entry->set(value.GetBool());
1538 case IVirtualEntry::Type::INT:
1539 entry->set(int(value.GetLong()));
1541 case IVirtualEntry::Type::FLOAT:
1542 entry->set(value.GetDouble());
1544 case IVirtualEntry::Type::VECTOR: {
1545 VectorProperty* vector = dynamic_cast<VectorProperty*>(prop);
1547 entry->set(vector->getVector());
1551 IntervalProperty* i = dynamic_cast<IntervalProperty*>(prop);
1553 entry->set(i->getInterval());
1557 std::string stringValue(wxString(value.GetString()));
1559 if (entry->getName() ==
"Name") {
1560 UniqueNameManager nameMgr = nodeMgr->makeUniqueNameManager();
1561 stringValue = nameMgr.getName(stringValue);
1563 entry->
set(stringValue);
1567 entry->
set(
Path(std::string(value.GetString())));
1571 EnumWrapper ew = entry->get();
1572 ew.value = value.GetLong();
1577 CurveProperty* curveProp = dynamic_cast<CurveProperty*>(prop);
1578 SPH_ASSERT(curveProp != nullptr);
1579 Curve curve = curveProp->getCurve();
1580 ExtraEntry extra(makeAuto<CurveEntry>(curve));
1591 this->updateProperties();
1594 this->updateEnabled(grid);
1596 nodeEditor->Refresh();
1597 callbacks->markUnsaved(
true);
1601 wxTreeCtrl* jobView =
1602 new wxTreeCtrl(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT);
1603 jobView->SetMinSize(wxSize(300, -1));
1605 wxTreeItemId rootId = jobView->AddRoot(
"Nodes");
1607 class JobTreeData :
public wxTreeItemData {
1618 std::string tooltip()
const {
1619 return desc->tooltip();
1625 const std::string& cat = desc->category();
1627 jobView->AppendItem(
id.value(), desc->className(), -1, -1,
new JobTreeData(desc.
get()));
1629 wxTreeItemId catId = jobView->AppendItem(rootId, cat);
1630 jobView->AppendItem(catId, desc->className(), -1, -1,
new JobTreeData(desc.
get()));
1631 categoryItemIdMap.
insert(cat, catId);
1635 wxTreeItemId presetsId = jobView->AppendItem(rootId,
"presets");
1636 std::map<wxTreeItemId, Presets::Id> presetsIdMap;
1637 for (
Presets::Id id : EnumMap::getAll<Presets::Id>()) {
1639 wxTreeItemId itemId = jobView->AppendItem(presetsId, name);
1640 presetsIdMap[itemId] = id;
1643 jobView->Bind(wxEVT_MOTION, [
this, jobView](wxMouseEvent& evt) {
1644 wxPoint pos = evt.GetPosition();
1646 wxTreeItemId
id = jobView->HitTest(pos, flags);
1649 if (flags & wxTREE_HITTEST_ONITEMLABEL) {
1650 JobTreeData* data =
dynamic_cast<JobTreeData*
>(jobView->GetItemData(
id));
1652 callback.
start(600, [
this, jobView,
id, data, pos] {
1653 const wxString name = jobView->GetItemText(
id);
1654 wxRichToolTip tip(name,
setLineBreak(data->tooltip(), 50));
1655 const wxRect rect(pos, pos);
1656 tip.ShowFor(jobView, &rect);
1657 tip.SetTimeout(1e6);
1659 nodeEditor->invalidateMousePosition();
1667 jobView->Bind(wxEVT_TREE_ITEM_ACTIVATED, [=](wxTreeEvent& evt) {
1668 wxTreeItemId
id = evt.GetItem();
1670 if (presetsIdMap.find(
id) != presetsIdMap.end()) {
1672 nodeMgr->addNodes(*presetNode);
1675 JobTreeData* data =
dynamic_cast<JobTreeData*
>(jobView->GetItemData(
id));
1682 settings.
set(
"file", path.
value());
1696 "Unknown file extension '" + path->extension().native() +
"'",
"Error", wxOK);
1702 VisNode* vis = nodeMgr->addNode(node);
1703 nodeEditor->activate(vis);
1704 this->selectNode(*node);
1705 callbacks->markUnsaved(
true);
1714 this->SetAutoLayout(
true);
1717 info.Left().MinSize(wxSize(300, -1));
1718 aui->AddPane(grid, info);
1719 aui->AddPane(nodeEditor, wxCENTER);
1722 aui->AddPane(jobView, info);
1725 panelInfoMap.insert(ID_LIST, &aui->GetPane(jobView));
1726 panelInfoMap.insert(ID_PROPERTIES, &aui->GetPane(grid));
1739 panelInfoMap[id]->Show();
1744 grid->CommitChangesFromEditor();
1747 this->updateProperties();
1751 grid->CommitChangesFromEditor();
1753 propertyEntryMap.
clear();
1758 this->updateProperties();
1779 grid->CommitChangesFromEditor();
1781 nodeMgr->
save(config);
1782 nodeEditor->
save(config);
1786 nodeMgr->
load(config);
1787 nodeEditor->
load(config);
1809 .MinSize(wxSize(300, 300))
1810 .CaptionVisible(
true)
1816 aui->AddPane(renderPane, info);
1823 void NodeWindow::updateProperties() {
1824 const wxString states = grid->SaveEditableState(wxPropertyGrid::ScrollPosState);
1826 propertyEntryMap.
clear();
1834 this->updateEnabled(grid);
1836 grid->RestoreEditableState(states, wxPropertyGrid::ScrollPosState);
1839 void NodeWindow::updateEnabled(wxPropertyGrid* grid) {
1840 for (wxPropertyGridIterator iter = grid->GetIterator(); !iter.AtEnd(); iter.Next()) {
1841 wxPGProperty* prop = iter.GetProperty();
1842 if (!propertyEntryMap.
contains(prop)) {
1848 const bool enabled = entry->
enabled();
1849 prop->Enable(enabled);
#define SPH_ASSERT(x,...)
#define NOT_IMPLEMENTED
Helper macro marking missing implementation.
Helper functions to check the internal consistency of the code.
@ NO_THROW
Function cannot throw exceptions.
@ MAIN_THREAD
Function can only be executed from main thread.
#define CHECK_FUNCTION(flags)
Interface for the configuration files storing job data.
uint32_t Size
Integral type used to index arrays (by default).
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
Helper objects allowing to iterate in reverse, iterate over multiple containeres, etc.
ReverseAdapter< TContainer > reverse(TContainer &&container)
ArrayView< const AutoPtr< IJobDesc > > enumerateRegisteredJobs()
Returns a view of all currently registered jobs.
RawPtr< IJobDesc > getJobDesc(const std::string &name)
Returns a job descriptor for given class name.
@ GEOMETRY
Job providing geometry.
@ MATERIAL
Job providing a material.
@ PARTICLES
Job providing particles.
constexpr INLINE T clamp(const T &f, const T &f1, const T &f2)
INLINE Float root(const Float f)
constexpr NAMESPACE_SPH_BEGIN int FIRST_SLOT_Y
constexpr int SLOT_RADIUS
SharedPtr< JobNode > cloneHierarchy(JobNode &node, const Optional< std::string > &prefix)
Clones all nodes in the hierarchy.
AutoPtr< JobNode > cloneNode(const JobNode &node, const std::string &name)
Clones a single node.
#define NAMESPACE_SPH_END
const NothingType NOTHING
INLINE RawPtr< T > addressOf(T &ref)
Additional bindings to IVirtualSettings.
std::string setLineBreak(const std::string &s, const Size lineWidth)
Inserts to string so that no line is longer than given limit.
std::string replaceAll(const std::string &source, const std::string &old, const std::string &s)
Replaces all occurences of string with a new string.
std::string capitalize(const std::string &input)
Capitalizes first letters of all words in the string, except for words like 'and',...
INLINE auto makeTuple(TArgs &&... args)
Creates a tuple from a pack of values, utilizing type deduction.
Optional< Path > doSaveFileDialog(const std::string &title, Array< FileFormat > &&formats)
Optional< Path > doOpenFileDialog(const std::string &title, Array< FileFormat > &&formats)
Random utility functions for drawing stuff to DC.
INLINE Float getLength(const Vector &v)
Returns the length of the vector. Enabled only for vectors of floating-point precision.
Array< IVirtualEntry::FileFormat > getInputFormats()
Convenience function, returning the list of input file formats defined by IoEnum.
Array< IVirtualEntry::FileFormat > getOutputFormats()
Convenience function, returning the list of output file formats defined by IoEnum.
virtual void onEntry(const std::string &UNUSED(key), IVirtualEntry &entry) const override
virtual void onCategory(const std::string &name) const override
Called for every category in the settings.
AddParamsProc(wxPropertyGrid *grid, PropertyEntryMap &propertyEntryMapping)
Generic dynamically allocated resizable storage.
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
INLINE TCounter size() const noexcept
INLINE T & front() noexcept
INLINE bool empty() const noexcept
Array clone() const
Performs a deep copy of all elements of the array.
INLINE RawPtr< T > get() const
BatchManager & getBatch()
virtual UnorderedMap< std::string, ExtJobType > getSlots() const override
Lists all potential inputs of the job.
BatchJob(const std::string &name, const Size runCnt)
virtual VirtualSettings getSettings() override
Returns a settings object which allows to query and modify the state of the job.
virtual std::string className() const override
Name representing the type of the job (e.e. "SPH").
virtual void evaluate(const RunSettings &UNUSED(global), IRunCallbacks &UNUSED(callbacks)) override
void save(Config &config)
Size getParamCount() const
void load(Config &config, ArrayView< const SharedPtr< JobNode >> nodes)
std::string getRunName(const Size rowIdx) const
void modifyHierarchy(const Size runIdx, JobNode &node)
Modifies the settings of the given node hierarchy.
BatchManager clone() const
SharedPtr< JobNode > getParamNode(const Size colIdx) const
Represents a single node in the hierarchy written into config file.
Optional< Type > tryGet(const std::string &name)
Tries to return a value stored in the node.
Type get(const std::string &name)
Returns a value stored in the node.
void set(const std::string &name, const Type &value)
Adds a new value into the node.
Provides functionality for reading and writing configuration files.
SharedPtr< ConfigNode > addNode(const std::string &name)
Adds a new node to the config.
SharedPtr< ConfigNode > getNode(const std::string &name)
Returns a node with given name.
void start(const int milliseconds, Function< void()> newCallback)
virtual bool DoShowDialog(wxPropertyGrid *UNUSED(propGrid), wxPGProperty *property) override
static Array< TEnum > getAll()
static std::string toString(const TEnum value)
virtual const char * what() const noexcept
void setFunc(Function< wxPGEditorDialogAdapter *()> func)
virtual wxPGEditorDialogAdapter * GetEditorDialog() const override
Container of key-value pairs.
INLINE bool contains(const TKey &key) const
Returns true if the map contains element of given key.
INLINE TValue & insert(const TKey &key, const TValue &value)
Adds a new element into the map or sets new value of element with the same key.
INLINE void clear()
Removes all elements from the map.
INLINE Optional< TValue & > tryGet(const TKey &key)
Returns a reference to the value matching the given key, or NOTHING if no such value exists.
virtual void startRun(SharedPtr< INode > node, const RunSettings &settings, const std::string &name) const =0
virtual void markUnsaved(bool addToUndo) const =0
Base class for all jobs providing particle data.
Callbacks executed by the simulation to provide feedback to the user.
Represents a virtual entry in the settings.
virtual bool set(const Value &value)=0
Modifies the current value of the entry.
virtual Array< FileFormat > getFileFormats() const
Returns the allowed file format for this file entry.
virtual bool isValid(const Value &value) const =0
Checks if the given value is a valid input for this entry.
virtual std::string getTooltip() const
Returns an optional description of the entry.
virtual Optional< PathType > getPathType() const
Returns the type of the path.
virtual std::string getName() const =0
Returns a descriptive name of the entry.
virtual bool hasSideEffect() const
Returns true if the entry can modify multiple values simultaneously.
virtual Value get() const =0
Returns the currently stored value.
virtual Type getType() const =0
Returns the type of this entry.
virtual bool enabled() const =0
Returns if this entry is currently enabled.
void update(const bool notify=true)
IntervalProperty(wxWindow *parent, const wxString &name, const Interval &value)
Interval getInterval() const
Object representing a 1D interval of real numbers.
INLINE Float lower() const
Returns lower bound of the interval.
INLINE Float upper() const
Returns upper bound of the interval.
Thrown when components of the run are mutually incompatible.
Building block of a simulation hierarchy.
Size getSlotCnt() const
Returns the number of provider slots of this node.
Size getDependentCnt() const
Returns the number of dependent nodes.
std::string instanceName() const
Returns the instance name of the job.
std::string className() const
Returns the class name of the job.
Optional< ExtJobType > provides() const
Returns the type of the job.
SlotData getSlot(const Size index) const
Returns the information about given slot.
void disconnect(SharedPtr< JobNode > dependent)
Disconnects this node from given dependent node.
void disconnectAll()
Disconnects all dependent nodes from this node.
void connect(SharedPtr< JobNode > dependent, const std::string &slotName)
Connects this node to given dependent node.
void enumerate(Function< void(const SharedPtr< JobNode > &job)> func)
Enumerates all nodes in the hierarchy.
VirtualSettings getSettings() const
Returns settings object allowing to access and modify the state of the job.
virtual void onCategory(const std::string &UNUSED(name)) const override
virtual void onEntry(const std::string &name, IVirtualEntry &entry) const override
Called for every entry in the current category.
LoadProc(ConfigNode &input)
void setNodeMgr(SharedPtr< NodeManager > mgr)
Pixel transform(const Pixel position) const
NodeEditor(NodeWindow *parent, SharedPtr< INodeManagerCallbacks > callbacks)
void save(Config &config)
Pixel offset
Translation of the panel.
void load(Config &config)
Optional< Pixel > mousePosition
const NodeMap & getNodes() const
Array< SharedPtr< JobNode > > getRootNodes() const
void startRun(JobNode &node)
void load(Config &config)
void startBatch(JobNode &node)
UniqueNameManager makeUniqueNameManager() const
VirtualSettings getGlobalSettings()
void addNodes(JobNode &node)
VisNode * getSelectedNode(const Pixel position)
void deleteNode(JobNode &node)
void startScript(const Path &file)
void layoutNodes(JobNode &node, const Pixel position)
NodeManager(NodeEditor *editor, SharedPtr< INodeManagerCallbacks > callbacks)
RenderPane * createRenderPreview(wxWindow *parent, JobNode &node)
NodeSlot getSlotAtPosition(const Pixel position)
void cloneHierarchy(JobNode &node)
VisNode * addNode(const SharedPtr< JobNode > &node)
void save(Config &config)
void deleteTree(JobNode &node)
void selectNode(const JobNode &node)
SharedPtr< JobNode > createNode(AutoPtr< IJob > &&job)
void addNode(const SharedPtr< JobNode > &node)
void load(Config &config)
UniqueNameManager makeUniqueNameManager() const
void addNodes(JobNode &node)
void showPanel(const PanelId id)
void save(Config &config)
NodeWindow(wxWindow *parent, SharedPtr< INodeManagerCallbacks > callbacks)
void createRenderPreview(JobNode &node)
void startScript(const Path &file)
OpenFileDialogAdapter(Array< FileFormat > &&formats)
virtual bool DoShowDialog(wxPropertyGrid *UNUSED(propGrid), wxPGProperty *property) override
INLINE Type & value()
Returns the reference to the stored value.
INLINE Type valueOr(const TOther &other) const
Returns the stored value if the object has been initialized, otherwise returns provided parameter.
Object representing a path on a filesystem.
std::string native() const
Returns the native version of the path.
wxPGProperty * addInterval(const std::string &name, const Interval &value) const
wxPGProperty * addInt(const std::string &name, const int value) const
PropertyGrid(wxPropertyGrid *grid)
wxPGProperty * addString(const std::string &name, const std::string &value) const
wxPGProperty * addFlags(const std::string &name, const IVirtualEntry &entry) const
wxPGProperty * addEnum(const std::string &name, const IVirtualEntry &entry) const
void setTooltip(wxPGProperty *prop, const std::string &tooltip) const
wxPGProperty * addExtra(const std::string &name, const ExtraEntry &extra) const
wxPGProperty * addFloat(const std::string &name, const Float value) const
wxPGProperty * addPath(const std::string &name, const Path &value, const IVirtualEntry::PathType type, Array< IVirtualEntry::FileFormat > &&formats) const
wxPGProperty * addCategory(const std::string &name) const
wxPGProperty * addBool(const std::string &name, const bool value) const
wxPGProperty * addVector(const std::string &name, const Vector &value) const
Non-owning wrapper of pointer.
Rgba brighten(const float amount) const
Returns a color brighter by given factor.
float intensity() const
Returns the average intensity of the color.
Rgba darken(const float amount) const
Returns a color darker by given factor.
Rgba blend(const Rgba &other, const float amount) const
Computes a linear interpolation of two color.
SharedPtr< JobNode > selectedNode() const
SaveFileDialogAdapter(Array< FileFormat > &&formats)
virtual bool DoShowDialog(wxPropertyGrid *UNUSED(propGrid), wxPGProperty *property) override
SaveProc(ConfigNode &out)
virtual void onCategory(const std::string &UNUSED(name)) const override
virtual void onEntry(const std::string &name, IVirtualEntry &entry) const override
Called for every entry in the current category.
Settings & set(const TEnum idx, TValue &&value, std::enable_if_t<!std::is_enum< std::decay_t< TValue >>::value, int >=0)
Saves a value into the settings.
SharedPtr< T > sharedFromThis() const
INLINE RawPtr< T > get() const
std::string getName(const std::string &name)
INLINE void clear()
Removes all elements from the map.
INLINE TValue & insert(const TKey &key, const TValue &value)
Adds a new element into the map or sets new value of element with the same key.
INLINE void remove(const TKey &key)
Removes element with given key from the map.
VectorProperty(wxWindow *parent, const wxString &name, const Vector &value)
void update(const bool notify=true)
EntryControl & connect(const std::string &name, const std::string &key, TValue &value)
Connects to given reference.
Interface allowing to enumerate all entries in the settings.
Holds a map of virtual entries, associated with a unique name.
void enumerate(const IEntryProc &proc)
Enumerates all entries stored in the settings.
void set(const std::string &key, const IVirtualEntry::Value &value)
Modifies an existing entry in the settings.
Category & addCategory(const std::string &name)
Creates a new category of entries.
SharedPtr< T > lock() const
Optional< IoEnum > getIoEnum(const std::string &ext)
Returns the file type from file extension.
@ UNIFORM
Mersenne Twister PRNG from Standard library.
@ SPHERICAL
Spherical mapping.
@ CUBIC_SPLINE
M4 B-spline (piecewise cubic polynomial)
@ RUN_AUTHOR
Name of the person running the simulation.
@ RUN_EMAIL
E-mail of the person running the simulation.
@ FINDER_LEAF_SIZE
Maximum number of particles in a leaf node.
@ SPH_KERNEL
Index of SPH Kernel, see KernelEnum.
@ GENERATE_UVWS
If true, the mapping coordinates will be computed and saved for all bodies in the simulation.
@ RUN_THREAD_CNT
Number of threads used by the code. If 0, all available threads are used.
@ RUN_COMMENT
User-specified comment.
@ RUN_OUTPUT_TYPE
Selected format of the output file, see IoEnum.
@ UVW_MAPPING
Type of the UV mapping.
@ RUN_RNG
Selected random-number generator used within the run.
@ RUN_RNG_SEED
Seed for the random-number generator.
@ FINDER_MAX_PARALLEL_DEPTH
@ RUN_OUTPUT_NAME
File name of the output file (including extension), where d is a placeholder for output number.
Vector position(const Float a, const Float e, const Float u)
Computes the position on the elliptic trajectory.
SharedPtr< JobNode > make(const Id id, UniqueNameManager &nameMgr, const Size particleCnt=10000)
Creates a node tree for the preset with given ID.
Overload of std::swap for Sph::Array.
void swap(Sph::Array< T, TCounter > &ar1, Sph::Array< T, TCounter > &ar2)
RawPtr< const VisNode > vis
static constexpr Size RESULT_SLOT
bool used
Whether the node is used by the job.
ExtJobType type
Specifies the type of the slot, or the type of the node connecting to it.
std::string name
Identifier of the slot, used by the job to obtain the provided data.
SharedPtr< JobNode > provider
Node currently connected to the slot.
static constexpr Size SIZE_X