diff --git a/BEdit/AGENTS.md b/BEdit/AGENTS.md
index 1be9003..010b527 100644
--- a/BEdit/AGENTS.md
+++ b/BEdit/AGENTS.md
@@ -111,6 +111,14 @@ Keep the root of `src/bedit` minimal. New UI modules should go into the relevant
per component instance from graph connections and exposed while compiling as
`$portname_N$`; array connection endpoints receive stable one-based indices in
graph connection order.
+- Blocking simulator integration belongs in `core/simulation/runner.py` and runs
+ on its daemon worker thread. Never perform OMPython startup or simulation work
+ directly on the Qt GUI thread; background failures must go to the application
+ log.
+- The optional OpenModelica executable is persisted as
+ `simulation/openModelicaPath`. The GUI passes it into `Simulation`; core must
+ not read `QSettings`. An empty path uses OMPython/PATH discovery, while an
+ explicit `.../bin/omc` path is converted to the OpenModelica home directory.
## Qt Designer and generated files
@@ -151,6 +159,9 @@ pyside6-uic --from-imports ui/text_definition_editor.ui \
pyside6-uic --from-imports ui/simulation_settings_dialog.ui \
-o src/bedit/gui/generated/ui_simulation_settings_dialog.py
+pyside6-uic --from-imports ui/graph_parameters_dialog.ui \
+ -o src/bedit/gui/generated/ui_graph_parameters_dialog.py
+
pyside6-uic --from-imports ui/parameter_options_dialog.ui \
-o src/bedit/gui/generated/ui_parameter_options_dialog.py
```
diff --git a/BEdit/pyproject.toml b/BEdit/pyproject.toml
index 790c93e..7d1bc00 100644
--- a/BEdit/pyproject.toml
+++ b/BEdit/pyproject.toml
@@ -11,6 +11,7 @@ requires-python = ">=3.10"
dependencies = [
"msgpack>=1.0,<2",
"PySide6>=6.7,<7",
+ "OMPython>4.0",
]
[project.optional-dependencies]
diff --git a/BEdit/src/bedit/core/simulation/runner.py b/BEdit/src/bedit/core/simulation/runner.py
new file mode 100644
index 0000000..9661922
--- /dev/null
+++ b/BEdit/src/bedit/core/simulation/runner.py
@@ -0,0 +1,68 @@
+import os
+from collections.abc import Callable
+from pathlib import Path
+from threading import Lock, Thread
+
+from bedit.core.application_log import get_logger
+
+
+log = get_logger(__name__)
+_worker_lock = Lock()
+_worker: Thread | None = None
+
+
+def run_simulation_async(
+ openmodelica_path: str = "", task: Callable[[], None] | None = None
+) -> None:
+ """Start one simulation task in a background thread and return immediately."""
+
+ global _worker
+ with _worker_lock:
+ if _worker is not None and _worker.is_alive():
+ raise RuntimeError("A simulation is already running")
+ _worker = Thread(
+ target=_run_safely,
+ args=(task or (lambda: _run_openmodelica(openmodelica_path)),),
+ name="bedit-simulation",
+ daemon=True,
+ )
+ _worker.start()
+
+
+def simulation_is_running() -> bool:
+ """Return whether the background simulation worker is active."""
+
+ with _worker_lock:
+ return _worker is not None and _worker.is_alive()
+
+
+def _run_safely(task: Callable[[], None]) -> None:
+ global _worker
+ try:
+ task()
+ except Exception:
+ log.exception("Simulation run failed")
+ finally:
+ with _worker_lock:
+ _worker = None
+
+
+def _run_openmodelica(openmodelica_path: str = "") -> None:
+ """Create the OpenModelica session and perform the current runner stub work."""
+
+ from OMPython import OMCSessionZMQ
+
+ omhome = _openmodelica_home(openmodelica_path)
+ omc = OMCSessionZMQ(omhome=omhome)
+ log.info("OpenModelica Version: %s", omc.sendExpression("getVersion()"))
+
+
+def _openmodelica_home(openmodelica_path: str) -> str | None:
+ """Convert an optional omc executable path to the home expected by OMPython."""
+
+ if not openmodelica_path.strip():
+ return None
+ path = Path(os.path.expandvars(openmodelica_path)).expanduser()
+ if path.name.lower() in {"omc", "omc.exe"}:
+ return str(path.parent.parent)
+ return str(path)
diff --git a/BEdit/src/bedit/core/simulation/service.py b/BEdit/src/bedit/core/simulation/service.py
index fddb3a0..389eb87 100644
--- a/BEdit/src/bedit/core/simulation/service.py
+++ b/BEdit/src/bedit/core/simulation/service.py
@@ -2,6 +2,7 @@ from typing import Any
from bedit.core.application_log import get_logger
from bedit.core.simulation.compiler import compile_graph
+from bedit.core.simulation.runner import run_simulation_async
log = get_logger(__name__)
@@ -10,11 +11,12 @@ log = get_logger(__name__)
class Simulation:
"""Application-owned simulation state and compiler facade."""
- def __init__(self) -> None:
+ def __init__(self, *, openmodelica_path: str = "") -> None:
self.state: dict[str, Any] = {}
self.last_compilation_input: dict[str, Any] | None = None
self.last_compilation_output: str | None = None
self.id_list: dict[str, Any] = {}
+ self.openmodelica_path = openmodelica_path
def compile(self, graph: dict[str, Any]) -> None:
"""Compile a serialized component tree and retain the result."""
@@ -24,4 +26,8 @@ class Simulation:
self.id_list = result.objects_by_id
self.last_compilation_output = result.modelica
log.info("Generated Modelica model:\n%s", self.last_compilation_output)
- log.info("Simulation settings:\n%s", self.last_compilation_input['implementation']['graph']['simulation'])
+
+ def run_simulation(self) -> None:
+ """Start the simulation without blocking the calling UI thread."""
+
+ run_simulation_async(self.openmodelica_path)
diff --git a/BEdit/src/bedit/gui/controllers/commands.py b/BEdit/src/bedit/gui/controllers/commands.py
index 155a805..b1a36f4 100644
--- a/BEdit/src/bedit/gui/controllers/commands.py
+++ b/BEdit/src/bedit/gui/controllers/commands.py
@@ -150,6 +150,19 @@ class EditSimulationSettingsCommand(QUndoCommand):
self.controller._set_simulation_settings(self.owner_id, self.old)
+class EditGraphParametersCommand(QUndoCommand):
+ def __init__(self, controller, old: dict, new: dict) -> None:
+ super().__init__("Edit graph parameters")
+ self.controller = controller
+ self.old, self.new = old, new
+
+ def redo(self) -> None:
+ self.controller._set_graph_parameters(self.new)
+
+ def undo(self) -> None:
+ self.controller._set_graph_parameters(self.old)
+
+
class DeleteAnnotationsCommand(QUndoCommand):
def __init__(self, controller, owner_id: str, annotations: dict[str, Annotation]) -> None:
super().__init__("Delete annotations")
diff --git a/BEdit/src/bedit/gui/controllers/document.py b/BEdit/src/bedit/gui/controllers/document.py
index ce12725..21c94e1 100644
--- a/BEdit/src/bedit/gui/controllers/document.py
+++ b/BEdit/src/bedit/gui/controllers/document.py
@@ -13,6 +13,7 @@ from bedit.gui.controllers.commands import (
DeleteSelectionCommand,
DeleteAnnotationsCommand,
EditGraphItemCommand,
+ EditGraphParametersCommand,
EditSimulationSettingsCommand,
EditTextDefinitionCommand,
EditComponentAppearanceCommand,
@@ -393,12 +394,45 @@ class DocumentController(QObject):
EditSimulationSettingsCommand(self, component.id, old, new)
)
+ def edit_graph_parameter_values(
+ self, root_id: str, values: dict[str, dict[str, str]]
+ ) -> None:
+ root = self.document.find_component(root_id) if self.document else None
+ if root is None:
+ return
+ subtree_ids = {component.id for component in self._component_subtree(root)}
+ if not set(values) <= subtree_ids:
+ raise ValueError("Parameter changes contain a component outside the active graph")
+
+ old: dict[str, list[dict]] = {}
+ new: dict[str, list[dict]] = {}
+ for component_id, parameter_values in values.items():
+ component = self.document.find_component(component_id)
+ known_ids = {parameter.id for parameter in component.parameters}
+ if not set(parameter_values) <= known_ids:
+ raise ValueError(f"Component {component.name!r} contains an unknown parameter")
+ updated = deepcopy(component.parameters)
+ for parameter in updated:
+ if parameter.id in parameter_values:
+ parameter.value = parameter_values[parameter.id]
+ old[component_id] = [parameter.to_dict() for parameter in component.parameters]
+ new[component_id] = [parameter.to_dict() for parameter in updated]
+
+ if old != new:
+ self.undo_stack.push(EditGraphParametersCommand(self, old, new))
+
def compile_active_graph(self) -> None:
component = self.active_component
if component is None or component.implementation_kind != "graph":
raise ValueError("Open a graph component before compiling")
self.simulation.compile(component.to_dict())
+ def run_simulation(self) -> None:
+ component = self.active_component
+ if component is None or component.implementation_kind != "graph":
+ raise ValueError("Open a graph component before running a simulation")
+ self.simulation.run_simulation()
+
def set_route_waypoints(self, item_kind: str, item_id: str, waypoints: list[QPointF]) -> None:
item = (
self.active_graph.connections
@@ -1082,6 +1116,22 @@ class DocumentController(QObject):
owner.graph.simulation_settings = deepcopy(settings)
self.documentReset.emit()
+ def _set_graph_parameters(self, values: dict[str, list[dict]]) -> None:
+ if self.document is None:
+ return
+ changed_text_components: list[str] = []
+ for component_id, parameters in values.items():
+ component = self.document.find_component(component_id)
+ if component is None:
+ continue
+ component.parameters = [Parameter.from_dict(item) for item in parameters]
+ if component.implementation_kind == "text":
+ changed_text_components.append(component_id)
+ self.document.validate()
+ self.documentReset.emit()
+ for component_id in changed_text_components:
+ self.textDefinitionChanged.emit(component_id)
+
def _replace_component(self, old_id: str, replacement: Component) -> None:
if self.document is None:
return
diff --git a/BEdit/src/bedit/gui/dialogs/graph_parameters.py b/BEdit/src/bedit/gui/dialogs/graph_parameters.py
new file mode 100644
index 0000000..b068eea
--- /dev/null
+++ b/BEdit/src/bedit/gui/dialogs/graph_parameters.py
@@ -0,0 +1,93 @@
+from copy import deepcopy
+
+from PySide6.QtCore import Qt
+from PySide6.QtWidgets import QDialog, QStyledItemDelegate, QTreeWidgetItem
+
+from bedit.core.model import Component
+from bedit.gui.generated.ui_graph_parameters_dialog import Ui_GraphParametersDialog
+
+
+COMPONENT_ID_ROLE = Qt.ItemDataRole.UserRole
+PARAMETER_ID_ROLE = Qt.ItemDataRole.UserRole + 1
+
+
+class ValueColumnDelegate(QStyledItemDelegate):
+ """Allow editing only in the parameter value column."""
+
+ def createEditor(self, parent, option, index): # noqa: N802 (Qt API name)
+ parameter_id = index.siblingAtColumn(0).data(PARAMETER_ID_ROLE)
+ if index.column() != 2 or parameter_id is None:
+ return None
+ return super().createEditor(parent, option, index)
+
+
+class GraphParametersDialog(QDialog):
+ """Edit every parameter value in an active component subtree."""
+
+ def __init__(self, root: Component, parent=None) -> None:
+ super().__init__(parent)
+ self.ui = Ui_GraphParametersDialog()
+ self.ui.setupUi(self)
+ self.ui.parameterTree.setItemDelegate(ValueColumnDelegate(self.ui.parameterTree))
+ self.setWindowTitle(f"Graph Parameters — {root.name}")
+ self._parameters = {
+ component.id: deepcopy(component.parameters)
+ for component in self._walk(root)
+ }
+ self._populate(root)
+ self.ui.parameterTree.expandAll()
+ self.ui.parameterTree.resizeColumnToContents(0)
+ self.ui.parameterTree.resizeColumnToContents(1)
+
+ @staticmethod
+ def _walk(component: Component):
+ yield component
+ if component.implementation_kind == "graph":
+ for child in component.graph.blocks.values():
+ yield from GraphParametersDialog._walk(child)
+
+ def _populate(self, root: Component) -> None:
+ self.ui.parameterTree.clear()
+
+ def add_component(component: Component, parent: QTreeWidgetItem | None) -> None:
+ item = QTreeWidgetItem([component.name, "", ""])
+ item.setData(0, COMPONENT_ID_ROLE, component.id)
+ item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEditable)
+ if parent is None:
+ self.ui.parameterTree.addTopLevelItem(item)
+ else:
+ parent.addChild(item)
+
+ for parameter in self._parameters[component.id]:
+ parameter_item = QTreeWidgetItem(
+ [parameter.name, parameter.type, parameter.value]
+ )
+ parameter_item.setData(0, COMPONENT_ID_ROLE, component.id)
+ parameter_item.setData(0, PARAMETER_ID_ROLE, parameter.id)
+ parameter_item.setFlags(
+ parameter_item.flags() | Qt.ItemFlag.ItemIsEditable
+ )
+ item.addChild(parameter_item)
+
+ if component.implementation_kind == "graph":
+ for child in component.graph.blocks.values():
+ add_component(child, item)
+
+ add_component(root, None)
+
+ @property
+ def parameter_values(self) -> dict[str, dict[str, str]]:
+ values: dict[str, dict[str, str]] = {}
+ iterator = self.ui.parameterTree.invisibleRootItem()
+
+ def collect(parent: QTreeWidgetItem) -> None:
+ for index in range(parent.childCount()):
+ item = parent.child(index)
+ parameter_id = item.data(0, PARAMETER_ID_ROLE)
+ if parameter_id is not None:
+ component_id = item.data(0, COMPONENT_ID_ROLE)
+ values.setdefault(component_id, {})[parameter_id] = item.text(2)
+ collect(item)
+
+ collect(iterator)
+ return values
diff --git a/BEdit/src/bedit/gui/dialogs/settings.py b/BEdit/src/bedit/gui/dialogs/settings.py
index c1bee8f..d6edea9 100644
--- a/BEdit/src/bedit/gui/dialogs/settings.py
+++ b/BEdit/src/bedit/gui/dialogs/settings.py
@@ -26,6 +26,7 @@ class SettingsDialog(QDialog):
self.ui.addLibraryFileButton.clicked.connect(self._add_library_file)
self.ui.addLibraryFolderButton.clicked.connect(self._add_library_folder)
self.ui.removeLibraryPathButton.clicked.connect(self._remove_library_path)
+ self.ui.browseOpenModelicaButton.clicked.connect(self._browse_openmodelica)
self.ui.libraryPathsList.itemSelectionChanged.connect(self._update_remove_button)
self.ui.syntaxStylesTable.cellDoubleClicked.connect(self._choose_syntax_color)
self._load_settings()
@@ -46,6 +47,7 @@ class SettingsDialog(QDialog):
self.ui.graphGridSpinBox.setValue(self.graph_grid_size(self.settings))
self.ui.graphSnapSpinBox.setValue(self.graph_snap_size(self.settings))
self.ui.iconGridSpinBox.setValue(self.icon_grid_size(self.settings))
+ self.ui.openModelicaPathEdit.setText(self.openmodelica_path(self.settings))
self._load_syntax_styles()
self._update_remove_button()
@@ -130,6 +132,25 @@ class SettingsDialog(QDialog):
settings = settings if settings is not None else application_settings()
return settings.value("grid/iconSize", 8, type=int)
+ @staticmethod
+ def openmodelica_path(settings: QSettings | None = None) -> str:
+ settings = settings if settings is not None else application_settings()
+ return str(settings.value("simulation/openModelicaPath", "") or "")
+
+ def _browse_openmodelica(self) -> None:
+ current = self.ui.openModelicaPathEdit.text().strip()
+ start = str(Path(current).expanduser().parent) if current else ""
+ path, _ = QFileDialog.getOpenFileName(
+ self,
+ "Select OpenModelica executable",
+ start,
+ "OpenModelica compiler (omc omc.exe);;All files (*)",
+ )
+ if path:
+ # Keep symlink paths such as ~/.local/bin/omc intact; resolving them
+ # could turn the selected launcher into an unrelated container script.
+ self.ui.openModelicaPathEdit.setText(str(Path(path).expanduser().absolute()))
+
def _add_library_file(self) -> None:
path, _ = QFileDialog.getOpenFileName(
self,
@@ -176,6 +197,10 @@ class SettingsDialog(QDialog):
self.settings.setValue("grid/graphSize", self.ui.graphGridSpinBox.value())
self.settings.setValue("grid/graphSnapSize", self.ui.graphSnapSpinBox.value())
self.settings.setValue("grid/iconSize", self.ui.iconGridSpinBox.value())
+ self.settings.setValue(
+ "simulation/openModelicaPath",
+ self.ui.openModelicaPathEdit.text().strip(),
+ )
for row in range(self.ui.syntaxStylesTable.rowCount()):
category = self.ui.syntaxStylesTable.item(row, 0).data(
Qt.ItemDataRole.UserRole
diff --git a/BEdit/src/bedit/gui/generated/ui_graph_parameters_dialog.py b/BEdit/src/bedit/gui/generated/ui_graph_parameters_dialog.py
new file mode 100644
index 0000000..2c081ec
--- /dev/null
+++ b/BEdit/src/bedit/gui/generated/ui_graph_parameters_dialog.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'graph_parameters_dialog.ui'
+##
+## Created by: Qt User Interface Compiler version 6.11.1
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+ QMetaObject, QObject, QPoint, QRect,
+ QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+ QFont, QFontDatabase, QGradient, QIcon,
+ QImage, QKeySequence, QLinearGradient, QPainter,
+ QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox,
+ QHeaderView, QLabel, QSizePolicy, QTreeWidget,
+ QTreeWidgetItem, QVBoxLayout, QWidget)
+
+class Ui_GraphParametersDialog(object):
+ def setupUi(self, GraphParametersDialog):
+ if not GraphParametersDialog.objectName():
+ GraphParametersDialog.setObjectName(u"GraphParametersDialog")
+ GraphParametersDialog.resize(620, 480)
+ self.dialogLayout = QVBoxLayout(GraphParametersDialog)
+ self.dialogLayout.setObjectName(u"dialogLayout")
+ self.descriptionLabel = QLabel(GraphParametersDialog)
+ self.descriptionLabel.setObjectName(u"descriptionLabel")
+
+ self.dialogLayout.addWidget(self.descriptionLabel)
+
+ self.parameterTree = QTreeWidget(GraphParametersDialog)
+ self.parameterTree.setObjectName(u"parameterTree")
+ self.parameterTree.setAlternatingRowColors(True)
+ self.parameterTree.setRootIsDecorated(True)
+ self.parameterTree.setColumnCount(3)
+
+ self.dialogLayout.addWidget(self.parameterTree)
+
+ self.buttonBox = QDialogButtonBox(GraphParametersDialog)
+ self.buttonBox.setObjectName(u"buttonBox")
+ self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Cancel|QDialogButtonBox.StandardButton.Ok)
+
+ self.dialogLayout.addWidget(self.buttonBox)
+
+
+ self.retranslateUi(GraphParametersDialog)
+ self.buttonBox.accepted.connect(GraphParametersDialog.accept)
+ self.buttonBox.rejected.connect(GraphParametersDialog.reject)
+
+ QMetaObject.connectSlotsByName(GraphParametersDialog)
+ # setupUi
+
+ def retranslateUi(self, GraphParametersDialog):
+ GraphParametersDialog.setWindowTitle(QCoreApplication.translate("GraphParametersDialog", u"Graph Parameters", None))
+ self.descriptionLabel.setText(QCoreApplication.translate("GraphParametersDialog", u"Edit parameter values throughout the active component tree.", None))
+ ___qtreewidgetitem = self.parameterTree.headerItem()
+ ___qtreewidgetitem.setText(2, QCoreApplication.translate("GraphParametersDialog", u"Value", None))
+ ___qtreewidgetitem.setText(1, QCoreApplication.translate("GraphParametersDialog", u"Type", None))
+ ___qtreewidgetitem.setText(0, QCoreApplication.translate("GraphParametersDialog", u"Component / Parameter", None))
+ # retranslateUi
+
diff --git a/BEdit/src/bedit/gui/generated/ui_main_window.py b/BEdit/src/bedit/gui/generated/ui_main_window.py
index c0eae2d..41d0d2c 100644
--- a/BEdit/src/bedit/gui/generated/ui_main_window.py
+++ b/BEdit/src/bedit/gui/generated/ui_main_window.py
@@ -36,84 +36,94 @@ class Ui_MainWindow(object):
icon = QIcon()
icon.addFile(u":/icons/icons/preferences-system.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.actionSimulationSettings.setIcon(icon)
+ self.actionGraphParameters = QAction(MainWindow)
+ self.actionGraphParameters.setObjectName(u"actionGraphParameters")
+ icon1 = QIcon()
+ icon1.addFile(u":/icons/icons/configure.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionGraphParameters.setIcon(icon1)
self.actionCompile = QAction(MainWindow)
self.actionCompile.setObjectName(u"actionCompile")
- icon1 = QIcon()
- icon1.addFile(u":/icons/icons/run-build.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionCompile.setIcon(icon1)
+ icon2 = QIcon()
+ icon2.addFile(u":/icons/icons/run-build.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionCompile.setIcon(icon2)
+ self.actionRunSimulation = QAction(MainWindow)
+ self.actionRunSimulation.setObjectName(u"actionRunSimulation")
+ icon3 = QIcon()
+ icon3.addFile(u":/icons/icons/media-playback-start.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionRunSimulation.setIcon(icon3)
self.actionNew = QAction(MainWindow)
self.actionNew.setObjectName(u"actionNew")
- icon2 = QIcon()
- icon2.addFile(u":/icons/icons/document-new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionNew.setIcon(icon2)
+ icon4 = QIcon()
+ icon4.addFile(u":/icons/icons/document-new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionNew.setIcon(icon4)
self.actionRotateClockwise = QAction(MainWindow)
self.actionRotateClockwise.setObjectName(u"actionRotateClockwise")
- icon3 = QIcon()
- icon3.addFile(u":/icons/icons/transform-rotate.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionRotateClockwise.setIcon(icon3)
+ icon5 = QIcon()
+ icon5.addFile(u":/icons/icons/transform-rotate.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionRotateClockwise.setIcon(icon5)
self.actionZoomIn = QAction(MainWindow)
self.actionZoomIn.setObjectName(u"actionZoomIn")
- icon4 = QIcon()
- icon4.addFile(u":/icons/icons/zoom-in.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionZoomIn.setIcon(icon4)
+ icon6 = QIcon()
+ icon6.addFile(u":/icons/icons/zoom-in.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionZoomIn.setIcon(icon6)
self.actionZoomOut = QAction(MainWindow)
self.actionZoomOut.setObjectName(u"actionZoomOut")
- icon5 = QIcon()
- icon5.addFile(u":/icons/icons/zoom-out.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionZoomOut.setIcon(icon5)
+ icon7 = QIcon()
+ icon7.addFile(u":/icons/icons/zoom-out.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionZoomOut.setIcon(icon7)
self.actionCenterView = QAction(MainWindow)
self.actionCenterView.setObjectName(u"actionCenterView")
- icon6 = QIcon()
- icon6.addFile(u":/icons/icons/zoom-original.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionCenterView.setIcon(icon6)
+ icon8 = QIcon()
+ icon8.addFile(u":/icons/icons/zoom-original.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionCenterView.setIcon(icon8)
self.actionOpen = QAction(MainWindow)
self.actionOpen.setObjectName(u"actionOpen")
- icon7 = QIcon()
- icon7.addFile(u":/icons/icons/document-open.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionOpen.setIcon(icon7)
+ icon9 = QIcon()
+ icon9.addFile(u":/icons/icons/document-open.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionOpen.setIcon(icon9)
self.actionReloadLibraries = QAction(MainWindow)
self.actionReloadLibraries.setObjectName(u"actionReloadLibraries")
self.actionReloadSimulation = QAction(MainWindow)
self.actionReloadSimulation.setObjectName(u"actionReloadSimulation")
self.actionSave = QAction(MainWindow)
self.actionSave.setObjectName(u"actionSave")
- icon8 = QIcon()
- icon8.addFile(u":/icons/icons/document-save.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionSave.setIcon(icon8)
+ icon10 = QIcon()
+ icon10.addFile(u":/icons/icons/document-save.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionSave.setIcon(icon10)
self.actionSaveAs = QAction(MainWindow)
self.actionSaveAs.setObjectName(u"actionSaveAs")
- icon9 = QIcon()
- icon9.addFile(u":/icons/icons/document-save-as.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionSaveAs.setIcon(icon9)
+ icon11 = QIcon()
+ icon11.addFile(u":/icons/icons/document-save-as.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionSaveAs.setIcon(icon11)
self.actionExit = QAction(MainWindow)
self.actionExit.setObjectName(u"actionExit")
self.actionClose = QAction(MainWindow)
self.actionClose.setObjectName(u"actionClose")
self.actionUndo = QAction(MainWindow)
self.actionUndo.setObjectName(u"actionUndo")
- icon10 = QIcon()
- icon10.addFile(u":/icons/icons/edit-undo.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionUndo.setIcon(icon10)
+ icon12 = QIcon()
+ icon12.addFile(u":/icons/icons/edit-undo.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionUndo.setIcon(icon12)
self.actionRedo = QAction(MainWindow)
self.actionRedo.setObjectName(u"actionRedo")
- icon11 = QIcon()
- icon11.addFile(u":/icons/icons/edit-redo.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionRedo.setIcon(icon11)
+ icon13 = QIcon()
+ icon13.addFile(u":/icons/icons/edit-redo.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionRedo.setIcon(icon13)
self.actionCut = QAction(MainWindow)
self.actionCut.setObjectName(u"actionCut")
- icon12 = QIcon()
- icon12.addFile(u":/icons/icons/edit-cut.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionCut.setIcon(icon12)
+ icon14 = QIcon()
+ icon14.addFile(u":/icons/icons/edit-cut.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionCut.setIcon(icon14)
self.actionCopy = QAction(MainWindow)
self.actionCopy.setObjectName(u"actionCopy")
- icon13 = QIcon()
- icon13.addFile(u":/icons/icons/edit-copy.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionCopy.setIcon(icon13)
+ icon15 = QIcon()
+ icon15.addFile(u":/icons/icons/edit-copy.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionCopy.setIcon(icon15)
self.actionPaste = QAction(MainWindow)
self.actionPaste.setObjectName(u"actionPaste")
- icon14 = QIcon()
- icon14.addFile(u":/icons/icons/edit-paste.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.actionPaste.setIcon(icon14)
+ icon16 = QIcon()
+ icon16.addFile(u":/icons/icons/edit-paste.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionPaste.setIcon(icon16)
self.actionSelectAll = QAction(MainWindow)
self.actionSelectAll.setObjectName(u"actionSelectAll")
self.actionDelete = QAction(MainWindow)
@@ -203,18 +213,18 @@ class Ui_MainWindow(object):
self.workspaceHeaderLayout.setContentsMargins(6, 2, 6, 2)
self.navigateUpButton = QToolButton(self.workspaceHeader)
self.navigateUpButton.setObjectName(u"navigateUpButton")
- icon15 = QIcon()
- icon15.addFile(u":/icons/icons/arrow-up.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.navigateUpButton.setIcon(icon15)
+ icon17 = QIcon()
+ icon17.addFile(u":/icons/icons/arrow-up.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.navigateUpButton.setIcon(icon17)
self.workspaceHeaderLayout.addWidget(self.navigateUpButton)
self.navigateDownButton = QToolButton(self.workspaceHeader)
self.navigateDownButton.setObjectName(u"navigateDownButton")
self.navigateDownButton.setEnabled(False)
- icon16 = QIcon()
- icon16.addFile(u":/icons/icons/arrow-down.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.navigateDownButton.setIcon(icon16)
+ icon18 = QIcon()
+ icon18.addFile(u":/icons/icons/arrow-down.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.navigateDownButton.setIcon(icon18)
self.workspaceHeaderLayout.addWidget(self.navigateDownButton)
@@ -234,9 +244,9 @@ class Ui_MainWindow(object):
self.pointerToolButton = QToolButton(self.workspaceHeader)
self.pointerToolButton.setObjectName(u"pointerToolButton")
- icon17 = QIcon()
- icon17.addFile(u":/icons/icons/edit-select.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.pointerToolButton.setIcon(icon17)
+ icon19 = QIcon()
+ icon19.addFile(u":/icons/icons/edit-select.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.pointerToolButton.setIcon(icon19)
self.pointerToolButton.setCheckable(True)
self.pointerToolButton.setChecked(True)
@@ -244,43 +254,43 @@ class Ui_MainWindow(object):
self.connectToolButton = QToolButton(self.workspaceHeader)
self.connectToolButton.setObjectName(u"connectToolButton")
- icon18 = QIcon()
- icon18.addFile(u":/icons/icons/network-connect.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.connectToolButton.setIcon(icon18)
+ icon20 = QIcon()
+ icon20.addFile(u":/icons/icons/network-connect.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.connectToolButton.setIcon(icon20)
self.connectToolButton.setCheckable(True)
self.workspaceHeaderLayout.addWidget(self.connectToolButton)
self.boxToolButton = QToolButton(self.workspaceHeader)
self.boxToolButton.setObjectName(u"boxToolButton")
- icon19 = QIcon()
- icon19.addFile(u":/icons/icons/draw-rectangle.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.boxToolButton.setIcon(icon19)
+ icon21 = QIcon()
+ icon21.addFile(u":/icons/icons/draw-rectangle.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.boxToolButton.setIcon(icon21)
self.boxToolButton.setCheckable(True)
self.workspaceHeaderLayout.addWidget(self.boxToolButton)
self.lineToolButton = QToolButton(self.workspaceHeader)
self.lineToolButton.setObjectName(u"lineToolButton")
- icon20 = QIcon()
- icon20.addFile(u":/icons/icons/draw-bezier-curves.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.lineToolButton.setIcon(icon20)
+ icon22 = QIcon()
+ icon22.addFile(u":/icons/icons/draw-bezier-curves.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.lineToolButton.setIcon(icon22)
self.lineToolButton.setCheckable(True)
self.workspaceHeaderLayout.addWidget(self.lineToolButton)
self.textToolButton = QToolButton(self.workspaceHeader)
self.textToolButton.setObjectName(u"textToolButton")
- icon21 = QIcon()
- icon21.addFile(u":/icons/icons/draw-text.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
- self.textToolButton.setIcon(icon21)
+ icon23 = QIcon()
+ icon23.addFile(u":/icons/icons/draw-text.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.textToolButton.setIcon(icon23)
self.textToolButton.setCheckable(True)
self.workspaceHeaderLayout.addWidget(self.textToolButton)
self.rotateToolButton = QToolButton(self.workspaceHeader)
self.rotateToolButton.setObjectName(u"rotateToolButton")
- self.rotateToolButton.setIcon(icon3)
+ self.rotateToolButton.setIcon(icon5)
self.workspaceHeaderLayout.addWidget(self.rotateToolButton)
@@ -433,7 +443,9 @@ class Ui_MainWindow(object):
self.cameraToolbar.addAction(self.actionZoomOut)
self.cameraToolbar.addAction(self.actionCenterView)
self.simulationToolbar.addAction(self.actionSimulationSettings)
+ self.simulationToolbar.addAction(self.actionGraphParameters)
self.simulationToolbar.addAction(self.actionCompile)
+ self.simulationToolbar.addAction(self.actionRunSimulation)
self.retranslateUi(MainWindow)
@@ -448,6 +460,10 @@ class Ui_MainWindow(object):
self.actionSimulationSettings.setText(QCoreApplication.translate("MainWindow", u"Simulation Settings", None))
#if QT_CONFIG(statustip)
self.actionSimulationSettings.setStatusTip(QCoreApplication.translate("MainWindow", u"Edit settings stored in the active graph", None))
+#endif // QT_CONFIG(statustip)
+ self.actionGraphParameters.setText(QCoreApplication.translate("MainWindow", u"Graph Parameters", None))
+#if QT_CONFIG(statustip)
+ self.actionGraphParameters.setStatusTip(QCoreApplication.translate("MainWindow", u"Edit parameters throughout the active graph", None))
#endif // QT_CONFIG(statustip)
self.actionCompile.setText(QCoreApplication.translate("MainWindow", u"Compile", None))
#if QT_CONFIG(statustip)
@@ -455,6 +471,13 @@ class Ui_MainWindow(object):
#endif // QT_CONFIG(statustip)
#if QT_CONFIG(shortcut)
self.actionCompile.setShortcut(QCoreApplication.translate("MainWindow", u"F5", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionRunSimulation.setText(QCoreApplication.translate("MainWindow", u"Run", None))
+#if QT_CONFIG(statustip)
+ self.actionRunSimulation.setStatusTip(QCoreApplication.translate("MainWindow", u"Run the simulation", None))
+#endif // QT_CONFIG(statustip)
+#if QT_CONFIG(shortcut)
+ self.actionRunSimulation.setShortcut(QCoreApplication.translate("MainWindow", u"F6", None))
#endif // QT_CONFIG(shortcut)
self.actionNew.setText(QCoreApplication.translate("MainWindow", u"&New", None))
#if QT_CONFIG(statustip)
diff --git a/BEdit/src/bedit/gui/generated/ui_settings_dialog.py b/BEdit/src/bedit/gui/generated/ui_settings_dialog.py
index 7e276a1..3c46d41 100644
--- a/BEdit/src/bedit/gui/generated/ui_settings_dialog.py
+++ b/BEdit/src/bedit/gui/generated/ui_settings_dialog.py
@@ -17,10 +17,10 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QAbstractButton, QAbstractItemView, QApplication, QDialog,
QDialogButtonBox, QFormLayout, QGroupBox, QHBoxLayout,
- QHeaderView, QLabel, QListWidget, QListWidgetItem,
- QPushButton, QSizePolicy, QSpacerItem, QSpinBox,
- QTabWidget, QTableWidget, QTableWidgetItem, QVBoxLayout,
- QWidget)
+ QHeaderView, QLabel, QLineEdit, QListWidget,
+ QListWidgetItem, QPushButton, QSizePolicy, QSpacerItem,
+ QSpinBox, QTabWidget, QTableWidget, QTableWidgetItem,
+ QVBoxLayout, QWidget)
class Ui_SettingsDialog(object):
def setupUi(self, SettingsDialog):
@@ -104,6 +104,48 @@ class Ui_SettingsDialog(object):
self.generalLayout.addItem(self.generalSpacer)
self.settingsTabs.addTab(self.generalTab, "")
+ self.simulationTab = QWidget()
+ self.simulationTab.setObjectName(u"simulationTab")
+ self.simulationTabLayout = QVBoxLayout(self.simulationTab)
+ self.simulationTabLayout.setObjectName(u"simulationTabLayout")
+ self.openModelicaGroupBox = QGroupBox(self.simulationTab)
+ self.openModelicaGroupBox.setObjectName(u"openModelicaGroupBox")
+ self.openModelicaLayout = QVBoxLayout(self.openModelicaGroupBox)
+ self.openModelicaLayout.setObjectName(u"openModelicaLayout")
+ self.openModelicaPathLabel = QLabel(self.openModelicaGroupBox)
+ self.openModelicaPathLabel.setObjectName(u"openModelicaPathLabel")
+
+ self.openModelicaLayout.addWidget(self.openModelicaPathLabel)
+
+ self.openModelicaPathLayout = QHBoxLayout()
+ self.openModelicaPathLayout.setObjectName(u"openModelicaPathLayout")
+ self.openModelicaPathEdit = QLineEdit(self.openModelicaGroupBox)
+ self.openModelicaPathEdit.setObjectName(u"openModelicaPathEdit")
+
+ self.openModelicaPathLayout.addWidget(self.openModelicaPathEdit)
+
+ self.browseOpenModelicaButton = QPushButton(self.openModelicaGroupBox)
+ self.browseOpenModelicaButton.setObjectName(u"browseOpenModelicaButton")
+
+ self.openModelicaPathLayout.addWidget(self.browseOpenModelicaButton)
+
+
+ self.openModelicaLayout.addLayout(self.openModelicaPathLayout)
+
+ self.openModelicaHintLabel = QLabel(self.openModelicaGroupBox)
+ self.openModelicaHintLabel.setObjectName(u"openModelicaHintLabel")
+ self.openModelicaHintLabel.setWordWrap(True)
+
+ self.openModelicaLayout.addWidget(self.openModelicaHintLabel)
+
+
+ self.simulationTabLayout.addWidget(self.openModelicaGroupBox)
+
+ self.simulationSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
+
+ self.simulationTabLayout.addItem(self.simulationSpacer)
+
+ self.settingsTabs.addTab(self.simulationTab, "")
self.syntaxTab = QWidget()
self.syntaxTab.setObjectName(u"syntaxTab")
self.syntaxTabLayout = QVBoxLayout(self.syntaxTab)
@@ -205,6 +247,12 @@ class Ui_SettingsDialog(object):
self.iconGridLabel.setText(QCoreApplication.translate("SettingsDialog", u"Icon grid size:", None))
self.iconGridSpinBox.setSuffix(QCoreApplication.translate("SettingsDialog", u" units", None))
self.settingsTabs.setTabText(self.settingsTabs.indexOf(self.generalTab), QCoreApplication.translate("SettingsDialog", u"General", None))
+ self.openModelicaGroupBox.setTitle(QCoreApplication.translate("SettingsDialog", u"OpenModelica", None))
+ self.openModelicaPathLabel.setText(QCoreApplication.translate("SettingsDialog", u"OpenModelica executable:", None))
+ self.openModelicaPathEdit.setPlaceholderText(QCoreApplication.translate("SettingsDialog", u"Leave empty to find omc on PATH", None))
+ self.browseOpenModelicaButton.setText(QCoreApplication.translate("SettingsDialog", u"Browse\u2026", None))
+ self.openModelicaHintLabel.setText(QCoreApplication.translate("SettingsDialog", u"Select the omc executable, for example ~/.local/bin/omc.", None))
+ self.settingsTabs.setTabText(self.settingsTabs.indexOf(self.simulationTab), QCoreApplication.translate("SettingsDialog", u"Simulation", None))
self.syntaxHintLabel.setText(QCoreApplication.translate("SettingsDialog", u"Double-click a colour cell to choose a colour. Word lists remain editable in data/syntax/openmodelica.json.", None))
___qtablewidgetitem = self.syntaxStylesTable.horizontalHeaderItem(0)
___qtablewidgetitem.setText(QCoreApplication.translate("SettingsDialog", u"Expression type", None))
diff --git a/BEdit/src/bedit/gui/main_window.py b/BEdit/src/bedit/gui/main_window.py
index 95ad7de..b3cd7c2 100644
--- a/BEdit/src/bedit/gui/main_window.py
+++ b/BEdit/src/bedit/gui/main_window.py
@@ -18,6 +18,7 @@ from bedit.core.serializer import DocumentSerializer
from bedit.core.simulation import Simulation
from bedit.gui.controllers.document import DocumentController
from bedit.gui.dialogs.component_options import ComponentOptionsDialog
+from bedit.gui.dialogs.graph_parameters import GraphParametersDialog
from bedit.gui.dialogs.item_options import ItemOptionsDialog
from bedit.gui.models.library_repository import LibraryRepository
from bedit.gui.models.library_tree import (
@@ -55,7 +56,9 @@ class MainWindow(QMainWindow):
self._applying_text_definition = False
self.libraries = LibraryRepository(self)
- self.simulation = Simulation()
+ self.simulation = Simulation(
+ openmodelica_path=SettingsDialog.openmodelica_path(self.settings)
+ )
self.document_controller = DocumentController(self, simulation=self.simulation)
self.library_tree_model = LibraryTreeModel(
self.libraries,
@@ -162,7 +165,9 @@ class MainWindow(QMainWindow):
self.ui.actionSimulationSettings.triggered.connect(
self.show_simulation_settings
)
+ self.ui.actionGraphParameters.triggered.connect(self.show_graph_parameters)
self.ui.actionCompile.triggered.connect(self.compile_active_graph)
+ self.ui.actionRunSimulation.triggered.connect(self.run_simulation)
self.document_controller.undo_stack.canUndoChanged.connect(self.ui.actionUndo.setEnabled)
self.document_controller.undo_stack.canRedoChanged.connect(self.ui.actionRedo.setEnabled)
self.document_controller.modifiedChanged.connect(lambda _modified: self._update_title())
@@ -218,6 +223,21 @@ class MainWindow(QMainWindow):
if dialog.exec() == dialog.DialogCode.Accepted:
self.document_controller.edit_simulation_settings(dialog.settings)
+ @Slot()
+ def show_graph_parameters(self) -> None:
+ component = self.document_controller.active_component
+ if component is None or component.implementation_kind != "graph":
+ return
+ dialog = GraphParametersDialog(component, self)
+ if dialog.exec() == dialog.DialogCode.Accepted:
+ try:
+ self.document_controller.edit_graph_parameter_values(
+ component.id, dialog.parameter_values
+ )
+ except ValueError as error:
+ self.log.error("Could not change graph parameters: %s", error)
+ QMessageBox.warning(self, "Cannot change graph parameters", str(error))
+
@Slot()
def compile_active_graph(self) -> None:
try:
@@ -226,6 +246,14 @@ class MainWindow(QMainWindow):
self.log.error("Compile failed: %s", error)
QMessageBox.warning(self, "Cannot compile", str(error))
+ @Slot()
+ def run_simulation(self) -> None:
+ try:
+ self.document_controller.run_simulation()
+ except Exception as error:
+ self.log.exception("Simulation run failed")
+ QMessageBox.warning(self, "Cannot run simulation", str(error))
+
def _restore_window_geometry(self) -> None:
geometry = self.settings.value("window/geometry")
if geometry is not None:
@@ -252,7 +280,9 @@ class MainWindow(QMainWindow):
self.ui.workspaceStack.setCurrentWidget(self.ui.emptyPage)
self._set_graph_controls_visible(False)
self.ui.actionSimulationSettings.setEnabled(False)
+ self.ui.actionGraphParameters.setEnabled(False)
self.ui.actionCompile.setEnabled(False)
+ self.ui.actionRunSimulation.setEnabled(False)
self._update_edit_actions()
return
self.ui.graphBreadcrumbLabel.setText(" › ".join(self.document_controller.breadcrumb()))
@@ -261,7 +291,9 @@ class MainWindow(QMainWindow):
)
is_graph = component.implementation_kind == "graph"
self.ui.actionSimulationSettings.setEnabled(is_graph)
+ self.ui.actionGraphParameters.setEnabled(is_graph)
self.ui.actionCompile.setEnabled(is_graph)
+ self.ui.actionRunSimulation.setEnabled(is_graph)
self.ui.workspaceModeLabel.setText("Graph" if is_graph else "Text")
self.ui.workspaceStack.setCurrentWidget(
self.ui.graphPage if is_graph else self.ui.textPage
@@ -483,8 +515,14 @@ class MainWindow(QMainWindow):
dialog = SettingsDialog(self)
dialog.settingsChanged.connect(self.reload_libraries)
dialog.settingsChanged.connect(self.refresh_editor_settings)
+ dialog.settingsChanged.connect(self.refresh_simulation_preferences)
dialog.exec()
+ def refresh_simulation_preferences(self) -> None:
+ self.simulation.openmodelica_path = SettingsDialog.openmodelica_path(
+ self.settings
+ )
+
def refresh_editor_settings(self) -> None:
scene = self.ui.graphView.scene()
if scene is not None:
diff --git a/BEdit/ui/graph_parameters_dialog.ui b/BEdit/ui/graph_parameters_dialog.ui
new file mode 100644
index 0000000..c595d44
--- /dev/null
+++ b/BEdit/ui/graph_parameters_dialog.ui
@@ -0,0 +1,35 @@
+
+
+ GraphParametersDialog
+
+ 00620480
+ Graph Parameters
+
+ -
+
+ Edit parameter values throughout the active component tree.
+
+
+ -
+
+ true
+ true
+ 3
+ Component / Parameter
+ Type
+ Value
+
+
+ -
+
+ QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok
+
+
+
+
+
+
+ buttonBoxaccepted()GraphParametersDialogaccept()
+ buttonBoxrejected()GraphParametersDialogreject()
+
+
diff --git a/BEdit/ui/main_window.ui b/BEdit/ui/main_window.ui
index 13c6069..884311c 100644
--- a/BEdit/ui/main_window.ui
+++ b/BEdit/ui/main_window.ui
@@ -633,7 +633,9 @@
false
+
+
@@ -647,6 +649,14 @@
Edit settings stored in the active graph
+
+
+
+ :/icons/icons/configure.png:/icons/icons/configure.png
+
+ Graph Parameters
+ Edit parameters throughout the active graph
+
@@ -662,6 +672,15 @@
F5
+
+
+
+ :/icons/icons/media-playback-start.png:/icons/icons/media-playback-start.png
+
+ Run
+ Run the simulation
+ F6
+
diff --git a/BEdit/ui/settings_dialog.ui b/BEdit/ui/settings_dialog.ui
index 80544b8..ae31987 100644
--- a/BEdit/ui/settings_dialog.ui
+++ b/BEdit/ui/settings_dialog.ui
@@ -86,6 +86,27 @@
+
+ Simulation
+
+ -
+
+ OpenModelica
+
+
- OpenModelica executable:
+ -
+
+
- Leave empty to find omc on PATH
+ - Browse…
+
+
+ - Select the omc executable, for example ~/.local/bin/omc.true
+
+
+
+ - Qt::Orientation::Vertical2040
+
+
Text highlighting
diff --git a/BEdit/untitled.bedit.json b/BEdit/untitled.bedit.json
index 958e5a8..6602f5f 100644
--- a/BEdit/untitled.bedit.json
+++ b/BEdit/untitled.bedit.json
@@ -96,7 +96,7 @@
"id": "parameter-022177fc",
"name": "v",
"type": "real",
- "value": "1"
+ "value": "2"
}
],
"icon": {