More types and units
This commit is contained in:
@@ -60,6 +60,10 @@ Keep the root of `src/bedit` minimal. New UI modules should go into the relevant
|
||||
indexes inputs and outputs separately for connection semantics.
|
||||
- Port types are registered in `core/port_types.py`. Only compatible types may be
|
||||
connected. `signal` is currently the only type.
|
||||
- Port connector type and signal value type are separate. Signal ports and
|
||||
parameters carry editable value type, quantity, unit, row/column dimensions,
|
||||
and description metadata. Editable quantity/unit suggestions live in
|
||||
`core/physical_types.py`; unlisted values remain valid.
|
||||
- Port removal or reorientation must be rejected when it would invalidate an
|
||||
existing connection.
|
||||
- Connections reference port IDs, never port names.
|
||||
@@ -168,6 +172,15 @@ Keep the root of `src/bedit` minimal. New UI modules should go into the relevant
|
||||
`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.
|
||||
- Builds enable OpenModelica's `--unitChecking`. Completed simulation results
|
||||
read per-column units from OMC's generated `<model>_init.xml`; BEdit must not
|
||||
infer derivative units itself. This metadata is serialized with `.ber`/JSON
|
||||
results and displayed by the simulation signal tree and plots.
|
||||
- Result loading restores variables marked `alias` or `negatedAlias` in OMC's
|
||||
initialization XML. Values come from OMC's result representative or a fixed
|
||||
parameter/constant start value; BEdit does not infer aliases from graph edges.
|
||||
- Compile requests call OMC `checkModel` before `buildModel` and log OMC's check
|
||||
summary verbatim through the application-wide logger.
|
||||
|
||||
## Qt Designer and generated files
|
||||
|
||||
|
||||
21
BEdit/m_Test.mo
Normal file
21
BEdit/m_Test.mo
Normal file
@@ -0,0 +1,21 @@
|
||||
model m_Test
|
||||
model m_Constant0
|
||||
output Real y(quantity="Length", unit="m");
|
||||
parameter Real v = 2;
|
||||
equation
|
||||
y = v;
|
||||
end m_Constant0;
|
||||
model m_Gain0
|
||||
input Real u;
|
||||
output Real y;
|
||||
parameter Real k(quantity="Current", unit="A") = 2.5;
|
||||
equation
|
||||
y = k*u;
|
||||
end m_Gain0;
|
||||
m_Constant0 Constant0;
|
||||
m_Gain0 Gain0;
|
||||
equation
|
||||
Gain0.u = Constant0.y;
|
||||
annotation(
|
||||
experiment(StartTime = 0, StopTime = 1, Tolerance = 1e-06, Interval = 0.002));
|
||||
end m_Test;
|
||||
@@ -8,6 +8,19 @@ from uuid import uuid4
|
||||
from bedit.core.port_types import PortTypeRegistry
|
||||
|
||||
|
||||
def _dimensions(data: Any, subject: str) -> tuple[int, int]:
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError(f"{subject} dimensions must be an object")
|
||||
try:
|
||||
rows = int(data.get("rows", 1))
|
||||
columns = int(data.get("columns", 1))
|
||||
except (TypeError, ValueError) as error:
|
||||
raise ValueError(f"{subject} dimensions must be whole numbers") from error
|
||||
if rows < 1 or columns < 1:
|
||||
raise ValueError(f"{subject} dimensions must be at least 1")
|
||||
return rows, columns
|
||||
|
||||
|
||||
@dataclass
|
||||
class Port:
|
||||
id: str
|
||||
@@ -17,6 +30,12 @@ class Port:
|
||||
properties: dict[str, Any] = field(default_factory=dict)
|
||||
type: str = "signal"
|
||||
allows_multiple_connections: bool = False
|
||||
value_type: str = "real"
|
||||
quantity: str = ""
|
||||
unit: str = ""
|
||||
rows: int = 1
|
||||
columns: int = 1
|
||||
description: str = ""
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
@@ -26,11 +45,17 @@ class Port:
|
||||
"properties": self.properties,
|
||||
"type": self.type,
|
||||
"multipleConnections": self.allows_multiple_connections,
|
||||
"valueType": self.value_type,
|
||||
"quantity": self.quantity,
|
||||
"unit": self.unit,
|
||||
"dimensions": {"rows": self.rows, "columns": self.columns},
|
||||
"description": self.description,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> "Port":
|
||||
position = data.get("position", {})
|
||||
rows, columns = _dimensions(data.get("dimensions", {}), "Port")
|
||||
return cls(
|
||||
id=str(data["id"]),
|
||||
name=str(data.get("name", data["id"])),
|
||||
@@ -39,6 +64,12 @@ class Port:
|
||||
properties=dict(data.get("properties", {})),
|
||||
type=str(data.get("type", "signal")),
|
||||
allows_multiple_connections=bool(data.get("multipleConnections", False)),
|
||||
value_type=str(data.get("valueType", "real")),
|
||||
quantity=str(data.get("quantity", "")),
|
||||
unit=str(data.get("unit", "")),
|
||||
rows=rows,
|
||||
columns=columns,
|
||||
description=str(data.get("description", "")),
|
||||
)
|
||||
|
||||
|
||||
@@ -166,9 +197,23 @@ class Parameter:
|
||||
name: str
|
||||
type: str = "real"
|
||||
value: str = "0"
|
||||
quantity: str = ""
|
||||
unit: str = ""
|
||||
rows: int = 1
|
||||
columns: int = 1
|
||||
description: str = ""
|
||||
|
||||
def to_dict(self) -> dict[str, str]:
|
||||
return {"id": self.id, "name": self.name, "type": self.type, "value": self.value}
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"type": self.type,
|
||||
"value": self.value,
|
||||
"quantity": self.quantity,
|
||||
"unit": self.unit,
|
||||
"dimensions": {"rows": self.rows, "columns": self.columns},
|
||||
"description": self.description,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> "Parameter":
|
||||
@@ -176,11 +221,17 @@ class Parameter:
|
||||
raise ValueError("Each component parameter must be an object")
|
||||
if "id" not in data:
|
||||
raise ValueError("Each component parameter must have an ID")
|
||||
rows, columns = _dimensions(data.get("dimensions", {}), "Parameter")
|
||||
return cls(
|
||||
id=str(data["id"]),
|
||||
name=str(data.get("name", "")),
|
||||
type=str(data.get("type", "real")),
|
||||
value=str(data.get("value", "0")),
|
||||
quantity=str(data.get("quantity", "")),
|
||||
unit=str(data.get("unit", "")),
|
||||
rows=rows,
|
||||
columns=columns,
|
||||
description=str(data.get("description", "")),
|
||||
)
|
||||
|
||||
|
||||
@@ -453,6 +504,13 @@ class GraphDocument:
|
||||
raise ValueError(f"Component {component.name!r} has duplicate parameter names")
|
||||
if any(not name.strip() for name in parameter_names):
|
||||
raise ValueError(f"Component {component.name!r} has an unnamed parameter")
|
||||
if any(not parameter.type.strip() for parameter in component.parameters):
|
||||
raise ValueError(f"Component {component.name!r} has an untyped parameter")
|
||||
if any(
|
||||
parameter.rows < 1 or parameter.columns < 1
|
||||
for parameter in component.parameters
|
||||
):
|
||||
raise ValueError(f"Component {component.name!r} has invalid parameter dimensions")
|
||||
if component.implementation_kind == "text" and component.graph.blocks:
|
||||
raise ValueError(f"Text component {component.name} cannot contain a graph")
|
||||
self._validate_graph(component)
|
||||
@@ -470,6 +528,10 @@ class GraphDocument:
|
||||
raise ValueError(f"Component {owner.name} contains duplicate port IDs")
|
||||
for port in (*owner.inputs, *owner.outputs):
|
||||
PortTypeRegistry.get(port.type)
|
||||
if not port.value_type.strip():
|
||||
raise ValueError(f"Port {port.name!r} has no value type")
|
||||
if port.rows < 1 or port.columns < 1:
|
||||
raise ValueError(f"Port {port.name!r} has invalid dimensions")
|
||||
for junction in owner.graph.junctions.values():
|
||||
PortTypeRegistry.get(junction.type)
|
||||
endpoint_counts: dict[tuple[str, str, str], int] = {}
|
||||
|
||||
47
BEdit/src/bedit/core/physical_types.py
Normal file
47
BEdit/src/bedit/core/physical_types.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""Editable suggestions for signal and parameter physical metadata.
|
||||
|
||||
These values populate editable combo boxes; documents may use values not listed
|
||||
here. They are suggestions rather than a validation registry.
|
||||
"""
|
||||
|
||||
VALUE_TYPES = ("real", "integer", "boolean", "string")
|
||||
|
||||
QUANTITIES = (
|
||||
"",
|
||||
"Angle",
|
||||
"AngularVelocity",
|
||||
"Current",
|
||||
"Energy",
|
||||
"Force",
|
||||
"Frequency",
|
||||
"Length",
|
||||
"Mass",
|
||||
"Power",
|
||||
"Pressure",
|
||||
"Temperature",
|
||||
"Time",
|
||||
"Torque",
|
||||
"Velocity",
|
||||
"Voltage",
|
||||
)
|
||||
|
||||
UNITS = (
|
||||
"",
|
||||
"1",
|
||||
"A",
|
||||
"Hz",
|
||||
"J",
|
||||
"K",
|
||||
"N",
|
||||
"N.m",
|
||||
"Pa",
|
||||
"V",
|
||||
"W",
|
||||
"deg",
|
||||
"kg",
|
||||
"m",
|
||||
"m/s",
|
||||
"rad",
|
||||
"rad/s",
|
||||
"s",
|
||||
)
|
||||
@@ -1,5 +1,5 @@
|
||||
from bedit.core.simulation.service import Simulation
|
||||
from bedit.core.simulation.openmodelica import OpenModelicaInterface
|
||||
from bedit.core.simulation.openmodelica import ModelBuildResult, OpenModelicaInterface
|
||||
from bedit.core.simulation.results import (
|
||||
BerSimulationResultsSerializer,
|
||||
JsonSimulationResultsSerializer,
|
||||
@@ -12,6 +12,7 @@ from bedit.core.simulation.results import (
|
||||
|
||||
__all__ = [
|
||||
"OpenModelicaInterface",
|
||||
"ModelBuildResult",
|
||||
"Simulation",
|
||||
"SimulationResults",
|
||||
"SimulationExecutionResult",
|
||||
|
||||
@@ -119,8 +119,11 @@ def emit_model(
|
||||
parameter_type = modelica_type(parameter.get("type", "real"))
|
||||
parameter_name = identifier(parameter["name"])
|
||||
value = expand_bevalues(str(parameter.get("value", "0")), macros)
|
||||
dimensions = _fixed_dimensions(parameter)
|
||||
attributes = _quantity_unit_attributes(parameter)
|
||||
lines.append(
|
||||
f"{body_indent}parameter {parameter_type} {parameter_name} = {value};"
|
||||
f"{body_indent}parameter {parameter_type} {parameter_name}"
|
||||
f"{dimensions}{attributes} = {value};"
|
||||
)
|
||||
|
||||
if implementation_kind == "text":
|
||||
@@ -213,14 +216,48 @@ def cleanup_graph(graph: dict[str, Any]) -> dict[str, Any]:
|
||||
def _port_declaration(
|
||||
port: dict[str, Any], direction: str, indent: int, macros: dict[str, str]
|
||||
) -> str:
|
||||
port_type = modelica_type(port.get("type", "signal"))
|
||||
port_type = modelica_type(port.get("valueType", "real"))
|
||||
indentation = "\t" * indent
|
||||
port_name = identifier(port["name"])
|
||||
dimension = f"[${port_name}_N$]" if port.get("multipleConnections", False) else ""
|
||||
declaration = f"{indentation}{direction} {port_type} {port_name}{dimension};"
|
||||
dimensions = _port_dimensions(port, port_name)
|
||||
attributes = _quantity_unit_attributes(port)
|
||||
declaration = (
|
||||
f"{indentation}{direction} {port_type} {port_name}{dimensions}{attributes};"
|
||||
)
|
||||
return expand_bevalues(declaration, macros)
|
||||
|
||||
|
||||
def _fixed_dimensions(item: dict[str, Any]) -> str:
|
||||
dimensions = item.get("dimensions", {})
|
||||
rows = max(1, int(dimensions.get("rows", 1)))
|
||||
columns = max(1, int(dimensions.get("columns", 1)))
|
||||
if rows == columns == 1:
|
||||
return ""
|
||||
if columns == 1:
|
||||
return f"[{rows}]"
|
||||
return f"[{rows},{columns}]"
|
||||
|
||||
|
||||
def _port_dimensions(port: dict[str, Any], port_name: str) -> str:
|
||||
fixed = _fixed_dimensions(port)
|
||||
if not port.get("multipleConnections", False):
|
||||
return fixed
|
||||
entries = [f"${port_name}_N$"]
|
||||
if fixed:
|
||||
entries.extend(fixed[1:-1].split(","))
|
||||
return f"[{','.join(entries)}]"
|
||||
|
||||
|
||||
def _quantity_unit_attributes(item: dict[str, Any]) -> str:
|
||||
attributes = []
|
||||
for key in ("quantity", "unit"):
|
||||
value = str(item.get(key, "")).strip()
|
||||
if value:
|
||||
escaped = value.replace("\\", "\\\\").replace('"', '\\"')
|
||||
attributes.append(f'{key}="{escaped}"')
|
||||
return f"({', '.join(attributes)})" if attributes else ""
|
||||
|
||||
|
||||
def _endpoint_expression(
|
||||
endpoint: dict[str, Any],
|
||||
owner: dict[str, Any],
|
||||
|
||||
@@ -48,6 +48,14 @@ class SimulationMessage:
|
||||
text: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ModelBuildResult:
|
||||
"""OMC's model check summary and subsequent build response."""
|
||||
|
||||
check_summary: str
|
||||
build_result: Any
|
||||
|
||||
|
||||
class OpenModelicaInterface:
|
||||
"""Asynchronous, persistent interface to one OpenModelica session.
|
||||
|
||||
@@ -92,10 +100,21 @@ class OpenModelicaInterface:
|
||||
"""Load and build one composed model as an ordered worker operation."""
|
||||
|
||||
def operation(omc, _temp_dir: Path):
|
||||
unit_checking = omc.sendExpression(
|
||||
'setCommandLineOptions("--unitChecking")'
|
||||
)
|
||||
if unit_checking is not True:
|
||||
raise RuntimeError("OpenModelica could not enable unit checking")
|
||||
loaded = omc.sendExpression(f"loadString({json.dumps(model)})")
|
||||
if loaded is not True:
|
||||
raise RuntimeError("OpenModelica could not load the composed model")
|
||||
return omc.sendExpression(f"buildModel({model_name})")
|
||||
check_summary = omc.sendExpression(f"checkModel({model_name})")
|
||||
if not isinstance(check_summary, str) or not check_summary.strip():
|
||||
raise RuntimeError(
|
||||
"OpenModelica did not return a model-check summary"
|
||||
)
|
||||
build_result = omc.sendExpression(f"buildModel({model_name})")
|
||||
return ModelBuildResult(check_summary, build_result)
|
||||
|
||||
self._submit("build model", operation, callback, error_callback)
|
||||
|
||||
@@ -334,16 +353,140 @@ def _run_model_with_tcp(
|
||||
f"OpenModelica did not create the expected result file {result_path.name!r}"
|
||||
)
|
||||
data = load_openmodelica_csv(result_path)
|
||||
init_path = temp_dir / f"{Path(executable).stem}_init.xml"
|
||||
csv_column_count = len(data)
|
||||
data = _add_openmodelica_alias_signals(init_path, data)
|
||||
signal_metadata = _load_openmodelica_signal_metadata(init_path, data)
|
||||
log.info(
|
||||
"Loaded %d result columns from %s", len(data), result_path.name
|
||||
"Loaded %d result columns, restored %d OMC aliases, and found %d "
|
||||
"unit definitions from %s",
|
||||
csv_column_count,
|
||||
len(data) - csv_column_count,
|
||||
len(signal_metadata),
|
||||
result_path.name,
|
||||
)
|
||||
return SimulationExecutionResult(
|
||||
return_code=int(return_code),
|
||||
result_file=str(result_path),
|
||||
data=data,
|
||||
signal_metadata=signal_metadata,
|
||||
)
|
||||
|
||||
|
||||
def _add_openmodelica_alias_signals(
|
||||
path: Path, data: dict[str, list[float]]
|
||||
) -> dict[str, list[float]]:
|
||||
"""Restore result aliases exactly as described by OMC's init XML."""
|
||||
|
||||
try:
|
||||
root = ET.parse(path).getroot()
|
||||
except (OSError, ET.ParseError) as error:
|
||||
raise RuntimeError(
|
||||
f"Could not read OpenModelica aliases from {path.name}: {error}"
|
||||
) from error
|
||||
|
||||
variables: dict[str, dict[str, str]] = {}
|
||||
for scalar in root.findall(".//ScalarVariable"):
|
||||
name = scalar.get("name", "")
|
||||
if not name:
|
||||
continue
|
||||
value = next(iter(scalar), None)
|
||||
variables[name] = {
|
||||
"alias": scalar.get("alias", "noAlias"),
|
||||
"target": scalar.get("aliasVariable", ""),
|
||||
"variability": scalar.get("variability", ""),
|
||||
"start": value.get("start", "") if value is not None else "",
|
||||
}
|
||||
|
||||
restored = {name: list(values) for name, values in data.items()}
|
||||
sample_count = len(next(iter(data.values()), []))
|
||||
|
||||
def resolve(name: str, visited: set[str] | None = None) -> list[float] | None:
|
||||
if name in restored:
|
||||
return restored[name]
|
||||
variable = variables.get(name)
|
||||
if variable is None:
|
||||
return None
|
||||
visited = set() if visited is None else visited
|
||||
if name in visited:
|
||||
return None
|
||||
visited.add(name)
|
||||
alias_kind = variable["alias"]
|
||||
target = variable["target"]
|
||||
if alias_kind in {"alias", "negatedAlias"} and target:
|
||||
values = resolve(target, visited)
|
||||
if values is None:
|
||||
return None
|
||||
return [-value for value in values] if alias_kind == "negatedAlias" else list(values)
|
||||
if variable["variability"] not in {"parameter", "constant"}:
|
||||
return None
|
||||
try:
|
||||
value = float(variable["start"])
|
||||
except ValueError:
|
||||
return None
|
||||
return [value] * sample_count
|
||||
|
||||
for name, variable in variables.items():
|
||||
if variable["alias"] not in {"alias", "negatedAlias"} or name in restored:
|
||||
continue
|
||||
values = resolve(name)
|
||||
if values is not None:
|
||||
restored[name] = values
|
||||
return restored
|
||||
|
||||
|
||||
def _load_openmodelica_signal_metadata(
|
||||
path: Path, signal_names: dict[str, list[float]]
|
||||
) -> dict[str, dict[str, str]]:
|
||||
"""Read units reported by OMC in its generated initialization XML."""
|
||||
|
||||
try:
|
||||
root = ET.parse(path).getroot()
|
||||
except (OSError, ET.ParseError) as error:
|
||||
raise RuntimeError(
|
||||
f"Could not read OpenModelica unit metadata from {path.name}: {error}"
|
||||
) from error
|
||||
|
||||
variables: dict[str, tuple[dict[str, str], str]] = {}
|
||||
for scalar in root.findall(".//ScalarVariable"):
|
||||
name = scalar.get("name", "")
|
||||
if not name:
|
||||
continue
|
||||
value = next(iter(scalar), None)
|
||||
metadata: dict[str, str] = {}
|
||||
if value is not None:
|
||||
for key in ("unit", "displayUnit", "quantity"):
|
||||
attribute = value.get(key, "")
|
||||
if attribute:
|
||||
metadata[key] = attribute
|
||||
description = scalar.get("description", "")
|
||||
if description:
|
||||
metadata["description"] = description
|
||||
variables[name] = (metadata, scalar.get("aliasVariable", ""))
|
||||
|
||||
def resolve(name: str, visited: set[str] | None = None) -> dict[str, str]:
|
||||
metadata, alias = variables.get(name, ({}, ""))
|
||||
if metadata.get("unit") or not alias:
|
||||
return dict(metadata)
|
||||
visited = set() if visited is None else visited
|
||||
if name in visited:
|
||||
return dict(metadata)
|
||||
visited.add(name)
|
||||
inherited = resolve(alias, visited)
|
||||
return {**inherited, **metadata}
|
||||
|
||||
metadata: dict[str, dict[str, str]] = {}
|
||||
for name in signal_names:
|
||||
if name not in variables:
|
||||
continue
|
||||
resolved = resolve(name)
|
||||
if resolved:
|
||||
metadata[name] = resolved
|
||||
if "time" in signal_names:
|
||||
metadata["time"] = {"unit": "s", "quantity": "Time"}
|
||||
return metadata
|
||||
|
||||
|
||||
def _accept_simulation_connection(
|
||||
server: socket.socket, command_finished: Event
|
||||
) -> socket.socket:
|
||||
|
||||
@@ -44,6 +44,7 @@ class SimulationResults:
|
||||
status: dict[str, Any] = field(default_factory=dict)
|
||||
messages: list[dict[str, str]] = field(default_factory=list)
|
||||
data: dict[str, list[float]] = field(default_factory=dict)
|
||||
signal_metadata: dict[str, dict[str, str]] = field(default_factory=dict)
|
||||
graphs: list[SimulationGraph] = field(
|
||||
default_factory=lambda: [SimulationGraph()]
|
||||
)
|
||||
@@ -57,6 +58,10 @@ class SimulationResults:
|
||||
"status": dict(self.status),
|
||||
"messages": [dict(message) for message in self.messages],
|
||||
"data": {name: list(values) for name, values in self.data.items()},
|
||||
"signalMetadata": {
|
||||
name: dict(metadata)
|
||||
for name, metadata in self.signal_metadata.items()
|
||||
},
|
||||
"graphs": [asdict(graph) for graph in self.graphs],
|
||||
"metadata": dict(self.metadata),
|
||||
}
|
||||
@@ -87,6 +92,15 @@ class SimulationResults:
|
||||
str(name): [float(value) for value in values]
|
||||
for name, values in dict(data.get("data", {})).items()
|
||||
},
|
||||
signal_metadata={
|
||||
str(name): {
|
||||
str(key): str(value)
|
||||
for key, value in dict(metadata).items()
|
||||
}
|
||||
for name, metadata in dict(
|
||||
data.get("signalMetadata", {})
|
||||
).items()
|
||||
},
|
||||
graphs=graphs,
|
||||
metadata=dict(data.get("metadata", {})),
|
||||
)
|
||||
@@ -101,6 +115,7 @@ class SimulationExecutionResult:
|
||||
return_code: int
|
||||
result_file: str
|
||||
data: dict[str, list[float]]
|
||||
signal_metadata: dict[str, dict[str, str]] = field(default_factory=dict)
|
||||
|
||||
|
||||
def load_openmodelica_csv(path: str | Path) -> dict[str, list[float]]:
|
||||
|
||||
@@ -5,6 +5,7 @@ from bedit.core.application_log import get_logger
|
||||
from bedit.core.simulation.composer import compose_graph
|
||||
from bedit.core.simulation.openmodelica import (
|
||||
ErrorCallback,
|
||||
ModelBuildResult,
|
||||
OpenModelicaInterface,
|
||||
ResultCallback,
|
||||
SimulationMessage,
|
||||
@@ -50,9 +51,19 @@ class Simulation:
|
||||
self.compose_source(graph)
|
||||
|
||||
def _model_compiled(result):
|
||||
log.info("Compiling OK: %s", result)
|
||||
if not isinstance(result, ModelBuildResult):
|
||||
failure = RuntimeError(
|
||||
f"OpenModelica returned an invalid build response: {result!r}"
|
||||
)
|
||||
if error_callback is not None:
|
||||
error_callback(failure)
|
||||
else:
|
||||
log.error("%s", failure)
|
||||
return
|
||||
log.info("%s", result.check_summary.strip())
|
||||
log.info("Compiling OK: %s", result.build_result)
|
||||
try:
|
||||
self.model_path = str(result[0])
|
||||
self.model_path = str(result.build_result[0])
|
||||
except (IndexError, TypeError) as error:
|
||||
failure = RuntimeError(
|
||||
f"OpenModelica returned an invalid build result: {result!r}"
|
||||
|
||||
@@ -5,6 +5,7 @@ from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QDialog, QListWidgetItem, QMessageBox
|
||||
|
||||
from bedit.core.model import Component, Parameter
|
||||
from bedit.core.physical_types import QUANTITIES, UNITS
|
||||
from bedit.gui.generated.ui_parameter_options_dialog import Ui_ParameterOptionsDialog
|
||||
|
||||
|
||||
@@ -22,19 +23,31 @@ class ParameterOptionsDialog(QDialog):
|
||||
self.parameters = deepcopy(component.parameters)
|
||||
self.read_only = read_only
|
||||
self._loading = False
|
||||
self.ui.quantityCombo.addItems(QUANTITIES)
|
||||
self.ui.unitCombo.addItems(UNITS)
|
||||
self.ui.parameterList.currentRowChanged.connect(self._load_current)
|
||||
self.ui.addParameterButton.clicked.connect(self.add_parameter)
|
||||
self.ui.removeParameterButton.clicked.connect(self.remove_parameter)
|
||||
self.ui.nameEdit.textEdited.connect(self._store_current)
|
||||
self.ui.typeEdit.textEdited.connect(self._store_current)
|
||||
self.ui.typeCombo.currentTextChanged.connect(self._store_current)
|
||||
self.ui.valueEdit.textEdited.connect(self._store_current)
|
||||
self.ui.quantityCombo.currentTextChanged.connect(self._store_current)
|
||||
self.ui.unitCombo.currentTextChanged.connect(self._store_current)
|
||||
self.ui.rowsSpin.valueChanged.connect(self._store_current)
|
||||
self.ui.columnsSpin.valueChanged.connect(self._store_current)
|
||||
self.ui.descriptionEdit.textChanged.connect(self._store_current)
|
||||
self.ui.parameterSplitter.setSizes([250, 370])
|
||||
if read_only:
|
||||
self.ui.addParameterButton.setEnabled(False)
|
||||
self.ui.removeParameterButton.setEnabled(False)
|
||||
self.ui.nameEdit.setReadOnly(True)
|
||||
self.ui.typeEdit.setReadOnly(True)
|
||||
self.ui.typeCombo.setEnabled(False)
|
||||
self.ui.valueEdit.setReadOnly(True)
|
||||
self.ui.quantityCombo.setEnabled(False)
|
||||
self.ui.unitCombo.setEnabled(False)
|
||||
self.ui.rowsSpin.setEnabled(False)
|
||||
self.ui.columnsSpin.setEnabled(False)
|
||||
self.ui.descriptionEdit.setReadOnly(True)
|
||||
self._rebuild_list(0 if self.parameters else -1)
|
||||
|
||||
def _rebuild_list(self, row: int = -1) -> None:
|
||||
@@ -51,12 +64,20 @@ class ParameterOptionsDialog(QDialog):
|
||||
if 0 <= row < len(self.parameters):
|
||||
parameter = self.parameters[row]
|
||||
self.ui.nameEdit.setText(parameter.name)
|
||||
self.ui.typeEdit.setText(parameter.type)
|
||||
self.ui.typeCombo.setCurrentText(parameter.type)
|
||||
self.ui.valueEdit.setText(parameter.value)
|
||||
self.ui.quantityCombo.setCurrentText(parameter.quantity)
|
||||
self.ui.unitCombo.setCurrentText(parameter.unit)
|
||||
self.ui.rowsSpin.setValue(parameter.rows)
|
||||
self.ui.columnsSpin.setValue(parameter.columns)
|
||||
self.ui.descriptionEdit.setPlainText(parameter.description)
|
||||
else:
|
||||
self.ui.nameEdit.clear()
|
||||
self.ui.typeEdit.clear()
|
||||
self.ui.typeCombo.setCurrentText("")
|
||||
self.ui.valueEdit.clear()
|
||||
self.ui.quantityCombo.setCurrentText("")
|
||||
self.ui.unitCombo.setCurrentText("")
|
||||
self.ui.descriptionEdit.clear()
|
||||
self._loading = False
|
||||
self._update_enabled()
|
||||
|
||||
@@ -64,8 +85,13 @@ class ParameterOptionsDialog(QDialog):
|
||||
enabled = self.ui.parameterList.currentRow() >= 0
|
||||
self.ui.removeParameterButton.setEnabled(enabled and not self.read_only)
|
||||
self.ui.nameEdit.setEnabled(enabled)
|
||||
self.ui.typeEdit.setEnabled(enabled)
|
||||
self.ui.typeCombo.setEnabled(enabled and not self.read_only)
|
||||
self.ui.valueEdit.setEnabled(enabled)
|
||||
self.ui.quantityCombo.setEnabled(enabled and not self.read_only)
|
||||
self.ui.unitCombo.setEnabled(enabled and not self.read_only)
|
||||
self.ui.rowsSpin.setEnabled(enabled and not self.read_only)
|
||||
self.ui.columnsSpin.setEnabled(enabled and not self.read_only)
|
||||
self.ui.descriptionEdit.setEnabled(enabled)
|
||||
|
||||
def _store_current(self) -> None:
|
||||
row = self.ui.parameterList.currentRow()
|
||||
@@ -73,8 +99,13 @@ class ParameterOptionsDialog(QDialog):
|
||||
return
|
||||
parameter = self.parameters[row]
|
||||
parameter.name = self.ui.nameEdit.text()
|
||||
parameter.type = self.ui.typeEdit.text()
|
||||
parameter.type = self.ui.typeCombo.currentText().strip() or "real"
|
||||
parameter.value = self.ui.valueEdit.text()
|
||||
parameter.quantity = self.ui.quantityCombo.currentText().strip()
|
||||
parameter.unit = self.ui.unitCombo.currentText().strip()
|
||||
parameter.rows = self.ui.rowsSpin.value()
|
||||
parameter.columns = self.ui.columnsSpin.value()
|
||||
parameter.description = self.ui.descriptionEdit.toPlainText()
|
||||
self.ui.parameterList.item(row).setText(
|
||||
f"{parameter.name} [{parameter.type}] = {parameter.value}"
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QDialog, QDialogButtonBox, QListWidgetItem, QMessageBox
|
||||
|
||||
from bedit.core.model import Component, Port
|
||||
from bedit.core.physical_types import QUANTITIES, UNITS
|
||||
from bedit.core.port_types import PortTypeRegistry
|
||||
from bedit.gui.generated.ui_port_options_dialog import Ui_PortOptionsDialog
|
||||
|
||||
@@ -20,6 +21,7 @@ class PortOptionsDialog(QDialog):
|
||||
self.ui = Ui_PortOptionsDialog()
|
||||
self.ui.setupUi(self)
|
||||
self.setWindowTitle(f"Port Options — {component.name}")
|
||||
self.read_only = read_only
|
||||
self.ports: list[tuple[Port, str]] = [
|
||||
*((deepcopy(port), "input") for port in component.inputs),
|
||||
*((deepcopy(port), "output") for port in component.outputs),
|
||||
@@ -28,15 +30,23 @@ class PortOptionsDialog(QDialog):
|
||||
self.ui.typeCombo.clear()
|
||||
for port_type in PortTypeRegistry.all():
|
||||
self.ui.typeCombo.addItem(port_type.display_name, port_type.id)
|
||||
self.ui.quantityCombo.addItems(QUANTITIES)
|
||||
self.ui.unitCombo.addItems(UNITS)
|
||||
self.ui.orientationCombo.setItemData(0, "input")
|
||||
self.ui.orientationCombo.setItemData(1, "output")
|
||||
self.ui.portList.currentRowChanged.connect(self._load_current)
|
||||
self.ui.addPortButton.clicked.connect(self.add_port)
|
||||
self.ui.removePortButton.clicked.connect(self.remove_port)
|
||||
self.ui.nameEdit.textEdited.connect(self._store_current)
|
||||
self.ui.typeCombo.currentIndexChanged.connect(self._store_current)
|
||||
self.ui.typeCombo.currentIndexChanged.connect(self._port_type_changed)
|
||||
self.ui.orientationCombo.currentIndexChanged.connect(self._store_current)
|
||||
self.ui.multipleConnectionsCheckBox.toggled.connect(self._store_current)
|
||||
self.ui.valueTypeCombo.currentTextChanged.connect(self._store_current)
|
||||
self.ui.quantityCombo.currentTextChanged.connect(self._store_current)
|
||||
self.ui.unitCombo.currentTextChanged.connect(self._store_current)
|
||||
self.ui.rowsSpin.valueChanged.connect(self._store_current)
|
||||
self.ui.columnsSpin.valueChanged.connect(self._store_current)
|
||||
self.ui.descriptionEdit.textChanged.connect(self._store_current)
|
||||
self.ui.portSplitter.setSizes([250, 370])
|
||||
if read_only:
|
||||
self.ui.addPortButton.setEnabled(False)
|
||||
@@ -45,6 +55,7 @@ class PortOptionsDialog(QDialog):
|
||||
self.ui.typeCombo.setEnabled(False)
|
||||
self.ui.orientationCombo.setEnabled(False)
|
||||
self.ui.multipleConnectionsCheckBox.setEnabled(False)
|
||||
self.ui.typeOptionsStack.setEnabled(False)
|
||||
self.ui.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText("Close")
|
||||
self.ui.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).hide()
|
||||
self._rebuild_list(0 if self.ports else -1)
|
||||
@@ -77,18 +88,38 @@ class PortOptionsDialog(QDialog):
|
||||
self.ui.multipleConnectionsCheckBox.setChecked(
|
||||
port.allows_multiple_connections
|
||||
)
|
||||
self.ui.valueTypeCombo.setCurrentText(port.value_type)
|
||||
self.ui.quantityCombo.setCurrentText(port.quantity)
|
||||
self.ui.unitCombo.setCurrentText(port.unit)
|
||||
self.ui.rowsSpin.setValue(port.rows)
|
||||
self.ui.columnsSpin.setValue(port.columns)
|
||||
self.ui.descriptionEdit.setPlainText(port.description)
|
||||
self._show_type_options(port.type)
|
||||
else:
|
||||
self.ui.nameEdit.clear()
|
||||
self.ui.descriptionEdit.clear()
|
||||
self._loading = False
|
||||
self._update_enabled()
|
||||
|
||||
def _update_enabled(self) -> None:
|
||||
enabled = self.ui.portList.currentRow() >= 0
|
||||
self.ui.removePortButton.setEnabled(enabled)
|
||||
self.ui.removePortButton.setEnabled(enabled and not self.read_only)
|
||||
self.ui.nameEdit.setEnabled(enabled)
|
||||
self.ui.typeCombo.setEnabled(enabled)
|
||||
self.ui.orientationCombo.setEnabled(enabled)
|
||||
self.ui.multipleConnectionsCheckBox.setEnabled(enabled)
|
||||
self.ui.typeCombo.setEnabled(enabled and not self.read_only)
|
||||
self.ui.orientationCombo.setEnabled(enabled and not self.read_only)
|
||||
self.ui.multipleConnectionsCheckBox.setEnabled(enabled and not self.read_only)
|
||||
self.ui.typeOptionsStack.setEnabled(enabled and not self.read_only)
|
||||
|
||||
def _port_type_changed(self) -> None:
|
||||
self._show_type_options(self.ui.typeCombo.currentData())
|
||||
self._store_current()
|
||||
|
||||
def _show_type_options(self, port_type: str) -> None:
|
||||
self.ui.typeOptionsStack.setCurrentWidget(
|
||||
self.ui.signalOptionsPage
|
||||
if port_type == "signal"
|
||||
else self.ui.unsupportedTypePage
|
||||
)
|
||||
|
||||
def _store_current(self) -> None:
|
||||
row = self.ui.portList.currentRow()
|
||||
@@ -98,6 +129,12 @@ class PortOptionsDialog(QDialog):
|
||||
port.name = self.ui.nameEdit.text()
|
||||
port.type = self.ui.typeCombo.currentData()
|
||||
port.allows_multiple_connections = self.ui.multipleConnectionsCheckBox.isChecked()
|
||||
port.value_type = self.ui.valueTypeCombo.currentText().strip() or "real"
|
||||
port.quantity = self.ui.quantityCombo.currentText().strip()
|
||||
port.unit = self.ui.unitCombo.currentText().strip()
|
||||
port.rows = self.ui.rowsSpin.value()
|
||||
port.columns = self.ui.columnsSpin.value()
|
||||
port.description = self.ui.descriptionEdit.toPlainText()
|
||||
self.ports[row] = (port, self.ui.orientationCombo.currentData())
|
||||
self.ui.portList.item(row).setText(
|
||||
f"{port.name} [{self.ports[row][1]}, {port.type}]"
|
||||
|
||||
@@ -26,10 +26,10 @@ class TextDefinitionEditor(QWidget):
|
||||
self._modified = False
|
||||
self._loading = False
|
||||
self.ui.portsTable.horizontalHeader().setSectionResizeMode(
|
||||
QHeaderView.ResizeMode.Stretch
|
||||
QHeaderView.ResizeMode.Interactive
|
||||
)
|
||||
self.ui.parametersTable.horizontalHeader().setSectionResizeMode(
|
||||
QHeaderView.ResizeMode.Stretch
|
||||
QHeaderView.ResizeMode.Interactive
|
||||
)
|
||||
self.ui.columnSplitter.setSizes([560, 340])
|
||||
self.ui.sourceSplitter.setSizes([180, 180, 240])
|
||||
@@ -78,6 +78,12 @@ class TextDefinitionEditor(QWidget):
|
||||
type=type_combo.currentData(),
|
||||
properties=deepcopy(name_item.data(PROPERTIES_ROLE) or {}),
|
||||
allows_multiple_connections=multiple_check.isChecked(),
|
||||
value_type=self.ui.portsTable.item(row, 4).text().strip() or "real",
|
||||
quantity=self.ui.portsTable.item(row, 5).text().strip(),
|
||||
unit=self.ui.portsTable.item(row, 6).text().strip(),
|
||||
rows=int(self.ui.portsTable.item(row, 7).text()),
|
||||
columns=int(self.ui.portsTable.item(row, 8).text()),
|
||||
description=self.ui.portsTable.item(row, 9).text(),
|
||||
)
|
||||
target = inputs if orientation_combo.currentData() == "input" else outputs
|
||||
target.append(port)
|
||||
@@ -92,6 +98,11 @@ class TextDefinitionEditor(QWidget):
|
||||
name=table.item(row, 0).text().strip(),
|
||||
type=table.item(row, 1).text().strip(),
|
||||
value=table.item(row, 2).text(),
|
||||
quantity=table.item(row, 3).text().strip(),
|
||||
unit=table.item(row, 4).text().strip(),
|
||||
rows=int(table.item(row, 5).text()),
|
||||
columns=int(table.item(row, 6).text()),
|
||||
description=table.item(row, 7).text(),
|
||||
)
|
||||
for row in range(table.rowCount())
|
||||
]
|
||||
@@ -138,8 +149,17 @@ class TextDefinitionEditor(QWidget):
|
||||
self._mark_modified()
|
||||
|
||||
def _refresh_editor_symbols(self) -> None:
|
||||
inputs, outputs = self.ports
|
||||
self._set_editor_symbols(inputs, outputs, self.parameters)
|
||||
inputs: list[str] = []
|
||||
outputs: list[str] = []
|
||||
for row in range(self.ui.portsTable.rowCount()):
|
||||
name_item = self.ui.portsTable.item(row, 0)
|
||||
orientation = self.ui.portsTable.cellWidget(row, 2).currentData()
|
||||
(inputs if orientation == "input" else outputs).append(name_item.text())
|
||||
parameters = [
|
||||
self.ui.parametersTable.item(row, 0).text()
|
||||
for row in range(self.ui.parametersTable.rowCount())
|
||||
]
|
||||
self._apply_editor_symbols(inputs, outputs, parameters)
|
||||
|
||||
def _set_editor_symbols(
|
||||
self,
|
||||
@@ -147,11 +167,16 @@ class TextDefinitionEditor(QWidget):
|
||||
outputs: list[Port],
|
||||
parameters: list[Parameter],
|
||||
) -> None:
|
||||
symbols = (
|
||||
self._apply_editor_symbols(
|
||||
[port.name for port in inputs],
|
||||
[port.name for port in outputs],
|
||||
[parameter.name for parameter in parameters],
|
||||
)
|
||||
|
||||
def _apply_editor_symbols(
|
||||
self, inputs: list[str], outputs: list[str], parameters: list[str]
|
||||
) -> None:
|
||||
symbols = (inputs, outputs, parameters)
|
||||
self.ui.declarationsEdit.set_symbols(*symbols)
|
||||
self.ui.initialEquationsEdit.set_symbols(*symbols)
|
||||
self.ui.equationsEdit.set_symbols(*symbols)
|
||||
@@ -183,6 +208,12 @@ class TextDefinitionEditor(QWidget):
|
||||
multiple.setChecked(port.allows_multiple_connections)
|
||||
multiple.toggled.connect(self._symbols_modified)
|
||||
table.setCellWidget(row, 3, multiple)
|
||||
table.setItem(row, 4, QTableWidgetItem(port.value_type))
|
||||
table.setItem(row, 5, QTableWidgetItem(port.quantity))
|
||||
table.setItem(row, 6, QTableWidgetItem(port.unit))
|
||||
table.setItem(row, 7, QTableWidgetItem(str(port.rows)))
|
||||
table.setItem(row, 8, QTableWidgetItem(str(port.columns)))
|
||||
table.setItem(row, 9, QTableWidgetItem(port.description))
|
||||
|
||||
def _append_parameter(self, parameter: Parameter) -> None:
|
||||
table = self.ui.parametersTable
|
||||
@@ -193,6 +224,11 @@ class TextDefinitionEditor(QWidget):
|
||||
table.setItem(row, 0, name)
|
||||
table.setItem(row, 1, QTableWidgetItem(parameter.type))
|
||||
table.setItem(row, 2, QTableWidgetItem(parameter.value))
|
||||
table.setItem(row, 3, QTableWidgetItem(parameter.quantity))
|
||||
table.setItem(row, 4, QTableWidgetItem(parameter.unit))
|
||||
table.setItem(row, 5, QTableWidgetItem(str(parameter.rows)))
|
||||
table.setItem(row, 6, QTableWidgetItem(str(parameter.columns)))
|
||||
table.setItem(row, 7, QTableWidgetItem(parameter.description))
|
||||
|
||||
def add_port(self) -> None:
|
||||
port = Port(
|
||||
|
||||
@@ -15,16 +15,17 @@ 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,
|
||||
QFormLayout, QHBoxLayout, QLabel, QLineEdit,
|
||||
QListWidget, QListWidgetItem, QPushButton, QSizePolicy,
|
||||
QSplitter, QVBoxLayout, QWidget)
|
||||
from PySide6.QtWidgets import (QAbstractButton, QApplication, QComboBox, QDialog,
|
||||
QDialogButtonBox, QFormLayout, QHBoxLayout, QLabel,
|
||||
QLineEdit, QListWidget, QListWidgetItem, QPlainTextEdit,
|
||||
QPushButton, QSizePolicy, QSpinBox, QSplitter,
|
||||
QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_ParameterOptionsDialog(object):
|
||||
def setupUi(self, ParameterOptionsDialog):
|
||||
if not ParameterOptionsDialog.objectName():
|
||||
ParameterOptionsDialog.setObjectName(u"ParameterOptionsDialog")
|
||||
ParameterOptionsDialog.resize(620, 380)
|
||||
ParameterOptionsDialog.resize(720, 500)
|
||||
self.dialogLayout = QVBoxLayout(ParameterOptionsDialog)
|
||||
self.dialogLayout.setObjectName(u"dialogLayout")
|
||||
self.parameterSplitter = QSplitter(ParameterOptionsDialog)
|
||||
@@ -76,20 +77,82 @@ class Ui_ParameterOptionsDialog(object):
|
||||
|
||||
self.parameterDetailsForm.setWidget(1, QFormLayout.ItemRole.LabelRole, self.typeLabel)
|
||||
|
||||
self.typeEdit = QLineEdit(self.parameterDetailsPanel)
|
||||
self.typeEdit.setObjectName(u"typeEdit")
|
||||
self.typeCombo = QComboBox(self.parameterDetailsPanel)
|
||||
self.typeCombo.addItem("")
|
||||
self.typeCombo.addItem("")
|
||||
self.typeCombo.addItem("")
|
||||
self.typeCombo.addItem("")
|
||||
self.typeCombo.setObjectName(u"typeCombo")
|
||||
self.typeCombo.setEditable(True)
|
||||
|
||||
self.parameterDetailsForm.setWidget(1, QFormLayout.ItemRole.FieldRole, self.typeEdit)
|
||||
self.parameterDetailsForm.setWidget(1, QFormLayout.ItemRole.FieldRole, self.typeCombo)
|
||||
|
||||
self.rowsLabel = QLabel(self.parameterDetailsPanel)
|
||||
self.rowsLabel.setObjectName(u"rowsLabel")
|
||||
|
||||
self.parameterDetailsForm.setWidget(2, QFormLayout.ItemRole.LabelRole, self.rowsLabel)
|
||||
|
||||
self.rowsSpin = QSpinBox(self.parameterDetailsPanel)
|
||||
self.rowsSpin.setObjectName(u"rowsSpin")
|
||||
self.rowsSpin.setMinimum(1)
|
||||
self.rowsSpin.setMaximum(9999)
|
||||
|
||||
self.parameterDetailsForm.setWidget(2, QFormLayout.ItemRole.FieldRole, self.rowsSpin)
|
||||
|
||||
self.columnsLabel = QLabel(self.parameterDetailsPanel)
|
||||
self.columnsLabel.setObjectName(u"columnsLabel")
|
||||
|
||||
self.parameterDetailsForm.setWidget(3, QFormLayout.ItemRole.LabelRole, self.columnsLabel)
|
||||
|
||||
self.columnsSpin = QSpinBox(self.parameterDetailsPanel)
|
||||
self.columnsSpin.setObjectName(u"columnsSpin")
|
||||
self.columnsSpin.setMinimum(1)
|
||||
self.columnsSpin.setMaximum(9999)
|
||||
|
||||
self.parameterDetailsForm.setWidget(3, QFormLayout.ItemRole.FieldRole, self.columnsSpin)
|
||||
|
||||
self.valueLabel = QLabel(self.parameterDetailsPanel)
|
||||
self.valueLabel.setObjectName(u"valueLabel")
|
||||
|
||||
self.parameterDetailsForm.setWidget(2, QFormLayout.ItemRole.LabelRole, self.valueLabel)
|
||||
self.parameterDetailsForm.setWidget(4, QFormLayout.ItemRole.LabelRole, self.valueLabel)
|
||||
|
||||
self.valueEdit = QLineEdit(self.parameterDetailsPanel)
|
||||
self.valueEdit.setObjectName(u"valueEdit")
|
||||
|
||||
self.parameterDetailsForm.setWidget(2, QFormLayout.ItemRole.FieldRole, self.valueEdit)
|
||||
self.parameterDetailsForm.setWidget(4, QFormLayout.ItemRole.FieldRole, self.valueEdit)
|
||||
|
||||
self.quantityLabel = QLabel(self.parameterDetailsPanel)
|
||||
self.quantityLabel.setObjectName(u"quantityLabel")
|
||||
|
||||
self.parameterDetailsForm.setWidget(5, QFormLayout.ItemRole.LabelRole, self.quantityLabel)
|
||||
|
||||
self.quantityCombo = QComboBox(self.parameterDetailsPanel)
|
||||
self.quantityCombo.setObjectName(u"quantityCombo")
|
||||
self.quantityCombo.setEditable(True)
|
||||
|
||||
self.parameterDetailsForm.setWidget(5, QFormLayout.ItemRole.FieldRole, self.quantityCombo)
|
||||
|
||||
self.unitLabel = QLabel(self.parameterDetailsPanel)
|
||||
self.unitLabel.setObjectName(u"unitLabel")
|
||||
|
||||
self.parameterDetailsForm.setWidget(6, QFormLayout.ItemRole.LabelRole, self.unitLabel)
|
||||
|
||||
self.unitCombo = QComboBox(self.parameterDetailsPanel)
|
||||
self.unitCombo.setObjectName(u"unitCombo")
|
||||
self.unitCombo.setEditable(True)
|
||||
|
||||
self.parameterDetailsForm.setWidget(6, QFormLayout.ItemRole.FieldRole, self.unitCombo)
|
||||
|
||||
self.descriptionLabel = QLabel(self.parameterDetailsPanel)
|
||||
self.descriptionLabel.setObjectName(u"descriptionLabel")
|
||||
|
||||
self.parameterDetailsForm.setWidget(7, QFormLayout.ItemRole.LabelRole, self.descriptionLabel)
|
||||
|
||||
self.descriptionEdit = QPlainTextEdit(self.parameterDetailsPanel)
|
||||
self.descriptionEdit.setObjectName(u"descriptionEdit")
|
||||
self.descriptionEdit.setMaximumHeight(100)
|
||||
|
||||
self.parameterDetailsForm.setWidget(7, QFormLayout.ItemRole.FieldRole, self.descriptionEdit)
|
||||
|
||||
self.parameterSplitter.addWidget(self.parameterDetailsPanel)
|
||||
|
||||
@@ -115,6 +178,16 @@ class Ui_ParameterOptionsDialog(object):
|
||||
self.removeParameterButton.setText(QCoreApplication.translate("ParameterOptionsDialog", u"Remove Parameter", None))
|
||||
self.nameLabel.setText(QCoreApplication.translate("ParameterOptionsDialog", u"Name:", None))
|
||||
self.typeLabel.setText(QCoreApplication.translate("ParameterOptionsDialog", u"Type:", None))
|
||||
self.typeCombo.setItemText(0, QCoreApplication.translate("ParameterOptionsDialog", u"real", None))
|
||||
self.typeCombo.setItemText(1, QCoreApplication.translate("ParameterOptionsDialog", u"integer", None))
|
||||
self.typeCombo.setItemText(2, QCoreApplication.translate("ParameterOptionsDialog", u"boolean", None))
|
||||
self.typeCombo.setItemText(3, QCoreApplication.translate("ParameterOptionsDialog", u"string", None))
|
||||
|
||||
self.rowsLabel.setText(QCoreApplication.translate("ParameterOptionsDialog", u"Rows:", None))
|
||||
self.columnsLabel.setText(QCoreApplication.translate("ParameterOptionsDialog", u"Columns:", None))
|
||||
self.valueLabel.setText(QCoreApplication.translate("ParameterOptionsDialog", u"Value:", None))
|
||||
self.quantityLabel.setText(QCoreApplication.translate("ParameterOptionsDialog", u"Quantity:", None))
|
||||
self.unitLabel.setText(QCoreApplication.translate("ParameterOptionsDialog", u"Unit:", None))
|
||||
self.descriptionLabel.setText(QCoreApplication.translate("ParameterOptionsDialog", u"Description:", None))
|
||||
# retranslateUi
|
||||
|
||||
|
||||
@@ -18,14 +18,14 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
from PySide6.QtWidgets import (QAbstractButton, QApplication, QCheckBox, QComboBox,
|
||||
QDialog, QDialogButtonBox, QFormLayout, QHBoxLayout,
|
||||
QLabel, QLineEdit, QListWidget, QListWidgetItem,
|
||||
QPushButton, QSizePolicy, QSplitter, QVBoxLayout,
|
||||
QWidget)
|
||||
QPlainTextEdit, QPushButton, QSizePolicy, QSpinBox,
|
||||
QSplitter, QStackedWidget, QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_PortOptionsDialog(object):
|
||||
def setupUi(self, PortOptionsDialog):
|
||||
if not PortOptionsDialog.objectName():
|
||||
PortOptionsDialog.setObjectName(u"PortOptionsDialog")
|
||||
PortOptionsDialog.resize(620, 380)
|
||||
PortOptionsDialog.resize(760, 421)
|
||||
self.dialogLayout = QVBoxLayout(PortOptionsDialog)
|
||||
self.dialogLayout.setObjectName(u"dialogLayout")
|
||||
self.portSplitter = QSplitter(PortOptionsDialog)
|
||||
@@ -61,6 +61,7 @@ class Ui_PortOptionsDialog(object):
|
||||
self.portDetailsPanel.setObjectName(u"portDetailsPanel")
|
||||
self.portDetailsForm = QFormLayout(self.portDetailsPanel)
|
||||
self.portDetailsForm.setObjectName(u"portDetailsForm")
|
||||
self.portDetailsForm.setVerticalSpacing(3)
|
||||
self.portDetailsForm.setContentsMargins(0, 0, 0, 0)
|
||||
self.nameLabel = QLabel(self.portDetailsPanel)
|
||||
self.nameLabel.setObjectName(u"nameLabel")
|
||||
@@ -104,7 +105,99 @@ class Ui_PortOptionsDialog(object):
|
||||
self.positionHintLabel.setObjectName(u"positionHintLabel")
|
||||
self.positionHintLabel.setWordWrap(True)
|
||||
|
||||
self.portDetailsForm.setWidget(4, QFormLayout.ItemRole.SpanningRole, self.positionHintLabel)
|
||||
self.portDetailsForm.setWidget(5, QFormLayout.ItemRole.SpanningRole, self.positionHintLabel)
|
||||
|
||||
self.typeOptionsStack = QStackedWidget(self.portDetailsPanel)
|
||||
self.typeOptionsStack.setObjectName(u"typeOptionsStack")
|
||||
self.signalOptionsPage = QWidget()
|
||||
self.signalOptionsPage.setObjectName(u"signalOptionsPage")
|
||||
self.signalOptionsForm = QFormLayout(self.signalOptionsPage)
|
||||
self.signalOptionsForm.setObjectName(u"signalOptionsForm")
|
||||
self.valueTypeLabel = QLabel(self.signalOptionsPage)
|
||||
self.valueTypeLabel.setObjectName(u"valueTypeLabel")
|
||||
|
||||
self.signalOptionsForm.setWidget(0, QFormLayout.ItemRole.LabelRole, self.valueTypeLabel)
|
||||
|
||||
self.valueTypeCombo = QComboBox(self.signalOptionsPage)
|
||||
self.valueTypeCombo.addItem("")
|
||||
self.valueTypeCombo.addItem("")
|
||||
self.valueTypeCombo.addItem("")
|
||||
self.valueTypeCombo.addItem("")
|
||||
self.valueTypeCombo.setObjectName(u"valueTypeCombo")
|
||||
self.valueTypeCombo.setEditable(True)
|
||||
|
||||
self.signalOptionsForm.setWidget(0, QFormLayout.ItemRole.FieldRole, self.valueTypeCombo)
|
||||
|
||||
self.quantityLabel = QLabel(self.signalOptionsPage)
|
||||
self.quantityLabel.setObjectName(u"quantityLabel")
|
||||
|
||||
self.signalOptionsForm.setWidget(1, QFormLayout.ItemRole.LabelRole, self.quantityLabel)
|
||||
|
||||
self.quantityCombo = QComboBox(self.signalOptionsPage)
|
||||
self.quantityCombo.setObjectName(u"quantityCombo")
|
||||
self.quantityCombo.setEditable(True)
|
||||
|
||||
self.signalOptionsForm.setWidget(1, QFormLayout.ItemRole.FieldRole, self.quantityCombo)
|
||||
|
||||
self.unitCombo = QComboBox(self.signalOptionsPage)
|
||||
self.unitCombo.setObjectName(u"unitCombo")
|
||||
self.unitCombo.setEditable(True)
|
||||
|
||||
self.signalOptionsForm.setWidget(2, QFormLayout.ItemRole.FieldRole, self.unitCombo)
|
||||
|
||||
self.unitLabel = QLabel(self.signalOptionsPage)
|
||||
self.unitLabel.setObjectName(u"unitLabel")
|
||||
|
||||
self.signalOptionsForm.setWidget(2, QFormLayout.ItemRole.LabelRole, self.unitLabel)
|
||||
|
||||
self.rowsColumnsLabel = QLabel(self.signalOptionsPage)
|
||||
self.rowsColumnsLabel.setObjectName(u"rowsColumnsLabel")
|
||||
|
||||
self.signalOptionsForm.setWidget(3, QFormLayout.ItemRole.LabelRole, self.rowsColumnsLabel)
|
||||
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.rowsSpin = QSpinBox(self.signalOptionsPage)
|
||||
self.rowsSpin.setObjectName(u"rowsSpin")
|
||||
self.rowsSpin.setMinimum(1)
|
||||
self.rowsSpin.setMaximum(9999)
|
||||
|
||||
self.horizontalLayout.addWidget(self.rowsSpin)
|
||||
|
||||
self.columnsSpin = QSpinBox(self.signalOptionsPage)
|
||||
self.columnsSpin.setObjectName(u"columnsSpin")
|
||||
self.columnsSpin.setMinimum(1)
|
||||
self.columnsSpin.setMaximum(9999)
|
||||
|
||||
self.horizontalLayout.addWidget(self.columnsSpin)
|
||||
|
||||
|
||||
self.signalOptionsForm.setLayout(3, QFormLayout.ItemRole.FieldRole, self.horizontalLayout)
|
||||
|
||||
self.descriptionLabel = QLabel(self.signalOptionsPage)
|
||||
self.descriptionLabel.setObjectName(u"descriptionLabel")
|
||||
|
||||
self.signalOptionsForm.setWidget(4, QFormLayout.ItemRole.LabelRole, self.descriptionLabel)
|
||||
|
||||
self.descriptionEdit = QPlainTextEdit(self.signalOptionsPage)
|
||||
self.descriptionEdit.setObjectName(u"descriptionEdit")
|
||||
|
||||
self.signalOptionsForm.setWidget(4, QFormLayout.ItemRole.FieldRole, self.descriptionEdit)
|
||||
|
||||
self.typeOptionsStack.addWidget(self.signalOptionsPage)
|
||||
self.unsupportedTypePage = QWidget()
|
||||
self.unsupportedTypePage.setObjectName(u"unsupportedTypePage")
|
||||
self.unsupportedTypeLayout = QVBoxLayout(self.unsupportedTypePage)
|
||||
self.unsupportedTypeLayout.setObjectName(u"unsupportedTypeLayout")
|
||||
self.unsupportedTypeLabel = QLabel(self.unsupportedTypePage)
|
||||
self.unsupportedTypeLabel.setObjectName(u"unsupportedTypeLabel")
|
||||
self.unsupportedTypeLabel.setWordWrap(True)
|
||||
|
||||
self.unsupportedTypeLayout.addWidget(self.unsupportedTypeLabel)
|
||||
|
||||
self.typeOptionsStack.addWidget(self.unsupportedTypePage)
|
||||
|
||||
self.portDetailsForm.setWidget(4, QFormLayout.ItemRole.SpanningRole, self.typeOptionsStack)
|
||||
|
||||
self.portSplitter.addWidget(self.portDetailsPanel)
|
||||
|
||||
@@ -129,7 +222,7 @@ class Ui_PortOptionsDialog(object):
|
||||
self.addPortButton.setText(QCoreApplication.translate("PortOptionsDialog", u"Add Port", None))
|
||||
self.removePortButton.setText(QCoreApplication.translate("PortOptionsDialog", u"Remove Port", None))
|
||||
self.nameLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"Name:", None))
|
||||
self.typeLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"Type:", None))
|
||||
self.typeLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"Port type:", None))
|
||||
self.typeCombo.setItemText(0, QCoreApplication.translate("PortOptionsDialog", u"Signal", None))
|
||||
|
||||
self.orientationLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"Orientation:", None))
|
||||
@@ -138,5 +231,16 @@ class Ui_PortOptionsDialog(object):
|
||||
|
||||
self.multipleConnectionsCheckBox.setText(QCoreApplication.translate("PortOptionsDialog", u"Allow multiple connections", None))
|
||||
self.positionHintLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"New ports start at (0, 0) in the icon editor.", None))
|
||||
self.valueTypeLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"Type:", None))
|
||||
self.valueTypeCombo.setItemText(0, QCoreApplication.translate("PortOptionsDialog", u"real", None))
|
||||
self.valueTypeCombo.setItemText(1, QCoreApplication.translate("PortOptionsDialog", u"integer", None))
|
||||
self.valueTypeCombo.setItemText(2, QCoreApplication.translate("PortOptionsDialog", u"boolean", None))
|
||||
self.valueTypeCombo.setItemText(3, QCoreApplication.translate("PortOptionsDialog", u"string", None))
|
||||
|
||||
self.quantityLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"Quantity:", None))
|
||||
self.unitLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"Unit:", None))
|
||||
self.rowsColumnsLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"Matrix size:", None))
|
||||
self.descriptionLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"Description:", None))
|
||||
self.unsupportedTypeLabel.setText(QCoreApplication.translate("PortOptionsDialog", u"This port type does not have an options editor yet.", None))
|
||||
# retranslateUi
|
||||
|
||||
|
||||
@@ -78,8 +78,8 @@ class Ui_TextDefinitionEditor(object):
|
||||
self.portsLayout = QVBoxLayout(self.portsGroup)
|
||||
self.portsLayout.setObjectName(u"portsLayout")
|
||||
self.portsTable = QTableWidget(self.portsGroup)
|
||||
if (self.portsTable.columnCount() < 4):
|
||||
self.portsTable.setColumnCount(4)
|
||||
if (self.portsTable.columnCount() < 10):
|
||||
self.portsTable.setColumnCount(10)
|
||||
__qtablewidgetitem = QTableWidgetItem()
|
||||
self.portsTable.setHorizontalHeaderItem(0, __qtablewidgetitem)
|
||||
__qtablewidgetitem1 = QTableWidgetItem()
|
||||
@@ -88,10 +88,22 @@ class Ui_TextDefinitionEditor(object):
|
||||
self.portsTable.setHorizontalHeaderItem(2, __qtablewidgetitem2)
|
||||
__qtablewidgetitem3 = QTableWidgetItem()
|
||||
self.portsTable.setHorizontalHeaderItem(3, __qtablewidgetitem3)
|
||||
__qtablewidgetitem4 = QTableWidgetItem()
|
||||
self.portsTable.setHorizontalHeaderItem(4, __qtablewidgetitem4)
|
||||
__qtablewidgetitem5 = QTableWidgetItem()
|
||||
self.portsTable.setHorizontalHeaderItem(5, __qtablewidgetitem5)
|
||||
__qtablewidgetitem6 = QTableWidgetItem()
|
||||
self.portsTable.setHorizontalHeaderItem(6, __qtablewidgetitem6)
|
||||
__qtablewidgetitem7 = QTableWidgetItem()
|
||||
self.portsTable.setHorizontalHeaderItem(7, __qtablewidgetitem7)
|
||||
__qtablewidgetitem8 = QTableWidgetItem()
|
||||
self.portsTable.setHorizontalHeaderItem(8, __qtablewidgetitem8)
|
||||
__qtablewidgetitem9 = QTableWidgetItem()
|
||||
self.portsTable.setHorizontalHeaderItem(9, __qtablewidgetitem9)
|
||||
self.portsTable.setObjectName(u"portsTable")
|
||||
self.portsTable.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
self.portsTable.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self.portsTable.setColumnCount(4)
|
||||
self.portsTable.setColumnCount(10)
|
||||
|
||||
self.portsLayout.addWidget(self.portsTable)
|
||||
|
||||
@@ -120,18 +132,28 @@ class Ui_TextDefinitionEditor(object):
|
||||
self.parametersLayout = QVBoxLayout(self.parametersGroup)
|
||||
self.parametersLayout.setObjectName(u"parametersLayout")
|
||||
self.parametersTable = QTableWidget(self.parametersGroup)
|
||||
if (self.parametersTable.columnCount() < 3):
|
||||
self.parametersTable.setColumnCount(3)
|
||||
__qtablewidgetitem4 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(0, __qtablewidgetitem4)
|
||||
__qtablewidgetitem5 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(1, __qtablewidgetitem5)
|
||||
__qtablewidgetitem6 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(2, __qtablewidgetitem6)
|
||||
if (self.parametersTable.columnCount() < 8):
|
||||
self.parametersTable.setColumnCount(8)
|
||||
__qtablewidgetitem10 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(0, __qtablewidgetitem10)
|
||||
__qtablewidgetitem11 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(1, __qtablewidgetitem11)
|
||||
__qtablewidgetitem12 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(2, __qtablewidgetitem12)
|
||||
__qtablewidgetitem13 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(3, __qtablewidgetitem13)
|
||||
__qtablewidgetitem14 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(4, __qtablewidgetitem14)
|
||||
__qtablewidgetitem15 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(5, __qtablewidgetitem15)
|
||||
__qtablewidgetitem16 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(6, __qtablewidgetitem16)
|
||||
__qtablewidgetitem17 = QTableWidgetItem()
|
||||
self.parametersTable.setHorizontalHeaderItem(7, __qtablewidgetitem17)
|
||||
self.parametersTable.setObjectName(u"parametersTable")
|
||||
self.parametersTable.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
self.parametersTable.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self.parametersTable.setColumnCount(3)
|
||||
self.parametersTable.setColumnCount(8)
|
||||
|
||||
self.parametersLayout.addWidget(self.parametersTable)
|
||||
|
||||
@@ -173,20 +195,42 @@ class Ui_TextDefinitionEditor(object):
|
||||
___qtablewidgetitem = self.portsTable.horizontalHeaderItem(0)
|
||||
___qtablewidgetitem.setText(QCoreApplication.translate("TextDefinitionEditor", u"Name", None))
|
||||
___qtablewidgetitem1 = self.portsTable.horizontalHeaderItem(1)
|
||||
___qtablewidgetitem1.setText(QCoreApplication.translate("TextDefinitionEditor", u"Type", None))
|
||||
___qtablewidgetitem1.setText(QCoreApplication.translate("TextDefinitionEditor", u"Port Type", None))
|
||||
___qtablewidgetitem2 = self.portsTable.horizontalHeaderItem(2)
|
||||
___qtablewidgetitem2.setText(QCoreApplication.translate("TextDefinitionEditor", u"Orientation", None))
|
||||
___qtablewidgetitem3 = self.portsTable.horizontalHeaderItem(3)
|
||||
___qtablewidgetitem3.setText(QCoreApplication.translate("TextDefinitionEditor", u"Multiple", None))
|
||||
___qtablewidgetitem4 = self.portsTable.horizontalHeaderItem(4)
|
||||
___qtablewidgetitem4.setText(QCoreApplication.translate("TextDefinitionEditor", u"Value Type", None))
|
||||
___qtablewidgetitem5 = self.portsTable.horizontalHeaderItem(5)
|
||||
___qtablewidgetitem5.setText(QCoreApplication.translate("TextDefinitionEditor", u"Quantity", None))
|
||||
___qtablewidgetitem6 = self.portsTable.horizontalHeaderItem(6)
|
||||
___qtablewidgetitem6.setText(QCoreApplication.translate("TextDefinitionEditor", u"Unit", None))
|
||||
___qtablewidgetitem7 = self.portsTable.horizontalHeaderItem(7)
|
||||
___qtablewidgetitem7.setText(QCoreApplication.translate("TextDefinitionEditor", u"Rows", None))
|
||||
___qtablewidgetitem8 = self.portsTable.horizontalHeaderItem(8)
|
||||
___qtablewidgetitem8.setText(QCoreApplication.translate("TextDefinitionEditor", u"Columns", None))
|
||||
___qtablewidgetitem9 = self.portsTable.horizontalHeaderItem(9)
|
||||
___qtablewidgetitem9.setText(QCoreApplication.translate("TextDefinitionEditor", u"Description", None))
|
||||
self.addPortButton.setText(QCoreApplication.translate("TextDefinitionEditor", u"Add Port", None))
|
||||
self.removePortButton.setText(QCoreApplication.translate("TextDefinitionEditor", u"Remove Port", None))
|
||||
self.parametersGroup.setTitle(QCoreApplication.translate("TextDefinitionEditor", u"Parameters", None))
|
||||
___qtablewidgetitem4 = self.parametersTable.horizontalHeaderItem(0)
|
||||
___qtablewidgetitem4.setText(QCoreApplication.translate("TextDefinitionEditor", u"Name", None))
|
||||
___qtablewidgetitem5 = self.parametersTable.horizontalHeaderItem(1)
|
||||
___qtablewidgetitem5.setText(QCoreApplication.translate("TextDefinitionEditor", u"Type", None))
|
||||
___qtablewidgetitem6 = self.parametersTable.horizontalHeaderItem(2)
|
||||
___qtablewidgetitem6.setText(QCoreApplication.translate("TextDefinitionEditor", u"Value", None))
|
||||
___qtablewidgetitem10 = self.parametersTable.horizontalHeaderItem(0)
|
||||
___qtablewidgetitem10.setText(QCoreApplication.translate("TextDefinitionEditor", u"Name", None))
|
||||
___qtablewidgetitem11 = self.parametersTable.horizontalHeaderItem(1)
|
||||
___qtablewidgetitem11.setText(QCoreApplication.translate("TextDefinitionEditor", u"Type", None))
|
||||
___qtablewidgetitem12 = self.parametersTable.horizontalHeaderItem(2)
|
||||
___qtablewidgetitem12.setText(QCoreApplication.translate("TextDefinitionEditor", u"Value", None))
|
||||
___qtablewidgetitem13 = self.parametersTable.horizontalHeaderItem(3)
|
||||
___qtablewidgetitem13.setText(QCoreApplication.translate("TextDefinitionEditor", u"Quantity", None))
|
||||
___qtablewidgetitem14 = self.parametersTable.horizontalHeaderItem(4)
|
||||
___qtablewidgetitem14.setText(QCoreApplication.translate("TextDefinitionEditor", u"Unit", None))
|
||||
___qtablewidgetitem15 = self.parametersTable.horizontalHeaderItem(5)
|
||||
___qtablewidgetitem15.setText(QCoreApplication.translate("TextDefinitionEditor", u"Rows", None))
|
||||
___qtablewidgetitem16 = self.parametersTable.horizontalHeaderItem(6)
|
||||
___qtablewidgetitem16.setText(QCoreApplication.translate("TextDefinitionEditor", u"Columns", None))
|
||||
___qtablewidgetitem17 = self.parametersTable.horizontalHeaderItem(7)
|
||||
___qtablewidgetitem17.setText(QCoreApplication.translate("TextDefinitionEditor", u"Description", None))
|
||||
self.addParameterButton.setText(QCoreApplication.translate("TextDefinitionEditor", u"Add Parameter", None))
|
||||
self.removeParameterButton.setText(QCoreApplication.translate("TextDefinitionEditor", u"Remove Parameter", None))
|
||||
pass
|
||||
|
||||
@@ -280,7 +280,20 @@ class SimulationWindow(QMainWindow):
|
||||
items[path] = item
|
||||
parent = item
|
||||
parent.setData(0, Qt.ItemDataRole.UserRole, signal_name)
|
||||
parent.setToolTip(0, signal_name)
|
||||
metadata = self.results.signal_metadata.get(signal_name, {})
|
||||
unit = metadata.get("unit", "")
|
||||
if unit:
|
||||
parent.setText(0, f"{parts[-1]} [{unit}]")
|
||||
tooltip = signal_name
|
||||
details = [
|
||||
metadata.get("quantity", ""),
|
||||
f"Unit: {unit}" if unit else "",
|
||||
metadata.get("description", ""),
|
||||
]
|
||||
details = [detail for detail in details if detail]
|
||||
if details:
|
||||
tooltip += "\n" + "\n".join(details)
|
||||
parent.setToolTip(0, tooltip)
|
||||
parent.setFlags(parent.flags() | Qt.ItemFlag.ItemIsUserCheckable)
|
||||
parent.setCheckState(0, Qt.CheckState.Unchecked)
|
||||
tree.expandToDepth(0)
|
||||
@@ -334,7 +347,14 @@ class SimulationWindow(QMainWindow):
|
||||
(trace for trace in graph.traces if trace.name == signal_name), None
|
||||
)
|
||||
if enabled and existing is None:
|
||||
graph.traces.append(SimulationTrace(name=signal_name))
|
||||
metadata = self.results.signal_metadata.get(signal_name, {})
|
||||
graph.traces.append(
|
||||
SimulationTrace(
|
||||
name=signal_name,
|
||||
y_label=metadata.get("quantity", ""),
|
||||
unit=metadata.get("unit", ""),
|
||||
)
|
||||
)
|
||||
elif not enabled and existing is not None:
|
||||
graph.traces.remove(existing)
|
||||
page = self.ui.graphTabs.currentWidget()
|
||||
@@ -492,6 +512,7 @@ class SimulationWindow(QMainWindow):
|
||||
self.results.status.update(phase="Simulation finished", progress=10000)
|
||||
if isinstance(result, SimulationExecutionResult):
|
||||
self.results.data = result.data
|
||||
self.results.signal_metadata = result.signal_metadata
|
||||
available_signals = set(result.data)
|
||||
for graph in self.results.graphs:
|
||||
graph.traces = [
|
||||
@@ -499,6 +520,10 @@ class SimulationWindow(QMainWindow):
|
||||
for trace in graph.traces
|
||||
if trace.name in available_signals
|
||||
]
|
||||
for trace in graph.traces:
|
||||
metadata = result.signal_metadata.get(trace.name, {})
|
||||
trace.unit = metadata.get("unit", "")
|
||||
trace.y_label = metadata.get("quantity", "")
|
||||
if graph.x_axis not in available_signals:
|
||||
graph.x_axis = (
|
||||
"time"
|
||||
@@ -570,14 +595,38 @@ class GraphWorkspacePage(QWidget):
|
||||
horizontal = x_values if x_values is not None else range(len(y_values))
|
||||
sample_count = min(len(horizontal), len(y_values))
|
||||
color = trace.properties.get("color")
|
||||
unit = trace.unit or self.results.signal_metadata.get(
|
||||
trace.name, {}
|
||||
).get("unit", "")
|
||||
label = f"{trace.name} [{unit}]" if unit else trace.name
|
||||
self.axes.plot(
|
||||
list(horizontal)[:sample_count],
|
||||
y_values[:sample_count],
|
||||
label=trace.name,
|
||||
label=label,
|
||||
color=color if isinstance(color, str) and color else None,
|
||||
)
|
||||
self.axes.set_title(self.graph.title)
|
||||
self.axes.set_xlabel(self.graph.x_axis if x_values is not None else "sample")
|
||||
if x_values is not None:
|
||||
x_unit = self.results.signal_metadata.get(
|
||||
self.graph.x_axis, {}
|
||||
).get("unit", "")
|
||||
x_label = (
|
||||
f"{self.graph.x_axis} [{x_unit}]"
|
||||
if x_unit
|
||||
else self.graph.x_axis
|
||||
)
|
||||
else:
|
||||
x_label = "sample"
|
||||
self.axes.set_xlabel(x_label)
|
||||
units = {
|
||||
trace.unit
|
||||
or self.results.signal_metadata.get(trace.name, {}).get("unit", "")
|
||||
for trace in self.graph.traces
|
||||
if self.results.data.get(trace.name) is not None
|
||||
}
|
||||
units.discard("")
|
||||
if len(units) == 1:
|
||||
self.axes.set_ylabel(next(iter(units)))
|
||||
self.axes.grid(True, alpha=0.25)
|
||||
if self.axes.lines:
|
||||
self.axes.legend()
|
||||
|
||||
@@ -2,13 +2,222 @@
|
||||
<ui version="4.0">
|
||||
<class>ParameterOptionsDialog</class>
|
||||
<widget class="QDialog" name="ParameterOptionsDialog">
|
||||
<property name="geometry"><rect><x>0</x><y>0</y><width>620</width><height>380</height></rect></property>
|
||||
<property name="windowTitle"><string>Parameter Options</string></property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>720</width>
|
||||
<height>328</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Parameter Options</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="dialogLayout">
|
||||
<item><widget class="QSplitter" name="parameterSplitter"><property name="orientation"><enum>Qt::Orientation::Horizontal</enum></property><widget class="QWidget" name="parameterListPanel"><layout class="QVBoxLayout" name="parameterListLayout"><item><widget class="QListWidget" name="parameterList"/></item><item><layout class="QHBoxLayout" name="parameterButtonsLayout"><item><widget class="QPushButton" name="addParameterButton"><property name="text"><string>Add Parameter</string></property></widget></item><item><widget class="QPushButton" name="removeParameterButton"><property name="text"><string>Remove Parameter</string></property></widget></item></layout></item></layout></widget><widget class="QWidget" name="parameterDetailsPanel"><layout class="QFormLayout" name="parameterDetailsForm"><item row="0" column="0"><widget class="QLabel" name="nameLabel"><property name="text"><string>Name:</string></property></widget></item><item row="0" column="1"><widget class="QLineEdit" name="nameEdit"/></item><item row="1" column="0"><widget class="QLabel" name="typeLabel"><property name="text"><string>Type:</string></property></widget></item><item row="1" column="1"><widget class="QLineEdit" name="typeEdit"/></item><item row="2" column="0"><widget class="QLabel" name="valueLabel"><property name="text"><string>Value:</string></property></widget></item><item row="2" column="1"><widget class="QLineEdit" name="valueEdit"/></item></layout></widget></widget></item>
|
||||
<item><widget class="QDialogButtonBox" name="buttonBox"><property name="standardButtons"><set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set></property></widget></item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="parameterSplitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="parameterListPanel">
|
||||
<layout class="QVBoxLayout" name="parameterListLayout">
|
||||
<item>
|
||||
<widget class="QListWidget" name="parameterList"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="parameterButtonsLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addParameterButton">
|
||||
<property name="text">
|
||||
<string>Add Parameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeParameterButton">
|
||||
<property name="text">
|
||||
<string>Remove Parameter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="parameterDetailsPanel">
|
||||
<layout class="QFormLayout" name="parameterDetailsForm">
|
||||
<property name="verticalSpacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="nameLabel">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="nameEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="typeLabel">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="typeCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>real</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>integer</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>boolean</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>string</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="columnsLabel">
|
||||
<property name="text">
|
||||
<string>Matrix size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="columnsSpin">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="rowsSpin">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="valueEdit"/>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="quantityCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="unitCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QPlainTextEdit" name="descriptionEdit"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="valueLabel">
|
||||
<property name="text">
|
||||
<string>Value:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="quantityLabel">
|
||||
<property name="text">
|
||||
<string>Quantity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="unitLabel">
|
||||
<property name="text">
|
||||
<string>Unit:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="descriptionLabel">
|
||||
<property name="text">
|
||||
<string>Description:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections><connection><sender>buttonBox</sender><signal>accepted()</signal><receiver>ParameterOptionsDialog</receiver><slot>accept()</slot><hints/></connection><connection><sender>buttonBox</sender><signal>rejected()</signal><receiver>ParameterOptionsDialog</receiver><slot>reject()</slot><hints/></connection></connections>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ParameterOptionsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ParameterOptionsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
||||
@@ -2,43 +2,288 @@
|
||||
<ui version="4.0">
|
||||
<class>PortOptionsDialog</class>
|
||||
<widget class="QDialog" name="PortOptionsDialog">
|
||||
<property name="geometry"><rect><x>0</x><y>0</y><width>620</width><height>380</height></rect></property>
|
||||
<property name="windowTitle"><string>Port Options</string></property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>760</width>
|
||||
<height>421</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Port Options</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="dialogLayout">
|
||||
<item>
|
||||
<widget class="QSplitter" name="portSplitter">
|
||||
<property name="orientation"><enum>Qt::Orientation::Horizontal</enum></property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="portListPanel">
|
||||
<layout class="QVBoxLayout" name="portListLayout">
|
||||
<item><widget class="QListWidget" name="portList"/></item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="portList"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="portButtonsLayout">
|
||||
<item><widget class="QPushButton" name="addPortButton"><property name="text"><string>Add Port</string></property></widget></item>
|
||||
<item><widget class="QPushButton" name="removePortButton"><property name="text"><string>Remove Port</string></property></widget></item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addPortButton">
|
||||
<property name="text">
|
||||
<string>Add Port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removePortButton">
|
||||
<property name="text">
|
||||
<string>Remove Port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="portDetailsPanel">
|
||||
<layout class="QFormLayout" name="portDetailsForm">
|
||||
<item row="0" column="0"><widget class="QLabel" name="nameLabel"><property name="text"><string>Name:</string></property></widget></item>
|
||||
<item row="0" column="1"><widget class="QLineEdit" name="nameEdit"/></item>
|
||||
<item row="1" column="0"><widget class="QLabel" name="typeLabel"><property name="text"><string>Type:</string></property></widget></item>
|
||||
<item row="1" column="1"><widget class="QComboBox" name="typeCombo"><item><property name="text"><string>Signal</string></property></item></widget></item>
|
||||
<item row="2" column="0"><widget class="QLabel" name="orientationLabel"><property name="text"><string>Orientation:</string></property></widget></item>
|
||||
<item row="2" column="1"><widget class="QComboBox" name="orientationCombo"><item><property name="text"><string>Input</string></property></item><item><property name="text"><string>Output</string></property></item></widget></item>
|
||||
<item row="3" column="0" colspan="2"><widget class="QCheckBox" name="multipleConnectionsCheckBox"><property name="text"><string>Allow multiple connections</string></property></widget></item>
|
||||
<item row="4" column="0" colspan="2"><widget class="QLabel" name="positionHintLabel"><property name="text"><string>New ports start at (0, 0) in the icon editor.</string></property><property name="wordWrap"><bool>true</bool></property></widget></item>
|
||||
<property name="verticalSpacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="nameLabel">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="nameEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="typeLabel">
|
||||
<property name="text">
|
||||
<string>Port type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="typeCombo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Signal</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="orientationLabel">
|
||||
<property name="text">
|
||||
<string>Orientation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="orientationCombo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Input</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Output</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="multipleConnectionsCheckBox">
|
||||
<property name="text">
|
||||
<string>Allow multiple connections</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QLabel" name="positionHintLabel">
|
||||
<property name="text">
|
||||
<string>New ports start at (0, 0) in the icon editor.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QStackedWidget" name="typeOptionsStack">
|
||||
<widget class="QWidget" name="signalOptionsPage">
|
||||
<layout class="QFormLayout" name="signalOptionsForm">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="valueTypeLabel">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="valueTypeCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>real</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>integer</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>boolean</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>string</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="quantityLabel">
|
||||
<property name="text">
|
||||
<string>Quantity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="quantityCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="unitCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="unitLabel">
|
||||
<property name="text">
|
||||
<string>Unit:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="rowsColumnsLabel">
|
||||
<property name="text">
|
||||
<string>Matrix size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="rowsSpin">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="columnsSpin">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="descriptionLabel">
|
||||
<property name="text">
|
||||
<string>Description:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QPlainTextEdit" name="descriptionEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="unsupportedTypePage">
|
||||
<layout class="QVBoxLayout" name="unsupportedTypeLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="unsupportedTypeLabel">
|
||||
<property name="text">
|
||||
<string>This port type does not have an options editor yet.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item><widget class="QDialogButtonBox" name="buttonBox"><property name="standardButtons"><set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set></property></widget></item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection><sender>buttonBox</sender><signal>accepted()</signal><receiver>PortOptionsDialog</receiver><slot>accept()</slot><hints/></connection>
|
||||
<connection><sender>buttonBox</sender><signal>rejected()</signal><receiver>PortOptionsDialog</receiver><slot>reject()</slot><hints/></connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>PortOptionsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>PortOptionsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
||||
@@ -40,14 +40,14 @@
|
||||
<widget class="QGroupBox" name="portsGroup">
|
||||
<property name="title"><string>Ports</string></property>
|
||||
<layout class="QVBoxLayout" name="portsLayout">
|
||||
<item><widget class="QTableWidget" name="portsTable"><property name="selectionBehavior"><enum>QAbstractItemView::SelectionBehavior::SelectRows</enum></property><property name="selectionMode"><enum>QAbstractItemView::SelectionMode::SingleSelection</enum></property><property name="columnCount"><number>4</number></property><column><property name="text"><string>Name</string></property></column><column><property name="text"><string>Type</string></property></column><column><property name="text"><string>Orientation</string></property></column><column><property name="text"><string>Multiple</string></property></column></widget></item>
|
||||
<item><widget class="QTableWidget" name="portsTable"><property name="selectionBehavior"><enum>QAbstractItemView::SelectionBehavior::SelectRows</enum></property><property name="selectionMode"><enum>QAbstractItemView::SelectionMode::SingleSelection</enum></property><property name="columnCount"><number>10</number></property><column><property name="text"><string>Name</string></property></column><column><property name="text"><string>Port Type</string></property></column><column><property name="text"><string>Orientation</string></property></column><column><property name="text"><string>Multiple</string></property></column><column><property name="text"><string>Value Type</string></property></column><column><property name="text"><string>Quantity</string></property></column><column><property name="text"><string>Unit</string></property></column><column><property name="text"><string>Rows</string></property></column><column><property name="text"><string>Columns</string></property></column><column><property name="text"><string>Description</string></property></column></widget></item>
|
||||
<item><layout class="QHBoxLayout" name="portButtonsLayout"><item><widget class="QPushButton" name="addPortButton"><property name="text"><string>Add Port</string></property></widget></item><item><widget class="QPushButton" name="removePortButton"><property name="text"><string>Remove Port</string></property></widget></item><item><spacer name="portButtonSpacer"><property name="orientation"><enum>Qt::Orientation::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item></layout></item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="parametersGroup">
|
||||
<property name="title"><string>Parameters</string></property>
|
||||
<layout class="QVBoxLayout" name="parametersLayout">
|
||||
<item><widget class="QTableWidget" name="parametersTable"><property name="selectionBehavior"><enum>QAbstractItemView::SelectionBehavior::SelectRows</enum></property><property name="selectionMode"><enum>QAbstractItemView::SelectionMode::SingleSelection</enum></property><property name="columnCount"><number>3</number></property><column><property name="text"><string>Name</string></property></column><column><property name="text"><string>Type</string></property></column><column><property name="text"><string>Value</string></property></column></widget></item>
|
||||
<item><widget class="QTableWidget" name="parametersTable"><property name="selectionBehavior"><enum>QAbstractItemView::SelectionBehavior::SelectRows</enum></property><property name="selectionMode"><enum>QAbstractItemView::SelectionMode::SingleSelection</enum></property><property name="columnCount"><number>8</number></property><column><property name="text"><string>Name</string></property></column><column><property name="text"><string>Type</string></property></column><column><property name="text"><string>Value</string></property></column><column><property name="text"><string>Quantity</string></property></column><column><property name="text"><string>Unit</string></property></column><column><property name="text"><string>Rows</string></property></column><column><property name="text"><string>Columns</string></property></column><column><property name="text"><string>Description</string></property></column></widget></item>
|
||||
<item><layout class="QHBoxLayout" name="parameterButtonsLayout"><item><widget class="QPushButton" name="addParameterButton"><property name="text"><string>Add Parameter</string></property></widget></item><item><widget class="QPushButton" name="removeParameterButton"><property name="text"><string>Remove Parameter</string></property></widget></item><item><spacer name="parameterButtonSpacer"><property name="orientation"><enum>Qt::Orientation::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item></layout></item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
"format": "bedit-document",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"name": "Untitled"
|
||||
"name": "Current Document"
|
||||
},
|
||||
"roots": [
|
||||
{
|
||||
"id": "6060fdd6-e816-4da9-8bb6-fde1a66d3e92",
|
||||
"name": "Test",
|
||||
"id": "4014ba90-5538-4050-a9be-552318197ce1",
|
||||
"name": "New Graph Block 1",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
@@ -52,9 +52,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"showName": false
|
||||
},
|
||||
"properties": {},
|
||||
"library": {
|
||||
"showSubtree": true
|
||||
},
|
||||
@@ -63,10 +61,10 @@
|
||||
"graph": {
|
||||
"blocks": [
|
||||
{
|
||||
"id": "2e6a192c-5aeb-45d6-80ee-d64a72392b76",
|
||||
"id": "86ba2bf6-0da5-40a4-98e9-fb0d9c12c576",
|
||||
"name": "Constant0",
|
||||
"position": {
|
||||
"x": -160.0,
|
||||
"x": -224.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
@@ -87,7 +85,15 @@
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
"multipleConnections": false,
|
||||
"valueType": "real",
|
||||
"quantity": "Length",
|
||||
"unit": "m",
|
||||
"dimensions": {
|
||||
"rows": 1,
|
||||
"columns": 1
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -96,7 +102,14 @@
|
||||
"id": "parameter-022177fc",
|
||||
"name": "v",
|
||||
"type": "real",
|
||||
"value": "2"
|
||||
"value": "2",
|
||||
"quantity": "",
|
||||
"unit": "",
|
||||
"dimensions": {
|
||||
"rows": 1,
|
||||
"columns": 1
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
],
|
||||
"icon": {
|
||||
@@ -172,10 +185,10 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "f4a78255-8b73-4bb3-ae8e-24b566c72bc0",
|
||||
"name": "gain0",
|
||||
"id": "7805cb2f-c938-44b2-a1f8-e1b4af13f7bf",
|
||||
"name": "Gain0",
|
||||
"position": {
|
||||
"x": -32.0,
|
||||
"x": -96.0,
|
||||
"y": -160.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
@@ -195,7 +208,15 @@
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
"multipleConnections": false,
|
||||
"valueType": "real",
|
||||
"quantity": "",
|
||||
"unit": "",
|
||||
"dimensions": {
|
||||
"rows": 1,
|
||||
"columns": 1
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
@@ -213,7 +234,15 @@
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
"multipleConnections": false,
|
||||
"valueType": "real",
|
||||
"quantity": "",
|
||||
"unit": "",
|
||||
"dimensions": {
|
||||
"rows": 1,
|
||||
"columns": 1
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -222,7 +251,14 @@
|
||||
"id": "parameter-61a43a86",
|
||||
"name": "k",
|
||||
"type": "real",
|
||||
"value": "2.5"
|
||||
"value": "2.5",
|
||||
"quantity": "Current",
|
||||
"unit": "A",
|
||||
"dimensions": {
|
||||
"rows": 1,
|
||||
"columns": 1
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
],
|
||||
"icon": {
|
||||
@@ -277,676 +313,28 @@
|
||||
"initialEquations": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "0b29c706-eb1b-4839-8ad2-bbed64efc01e",
|
||||
"name": "const_and_time",
|
||||
"position": {
|
||||
"x": -160.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"interface": {
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "port-ddc97277",
|
||||
"name": "y",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"properties": {
|
||||
"iconPosition": {
|
||||
"x": 88.0,
|
||||
"y": 40.0
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"id": "parameter-022177fc",
|
||||
"name": "v",
|
||||
"type": "real",
|
||||
"value": "4.8"
|
||||
}
|
||||
],
|
||||
"icon": {
|
||||
"shape": "rectangle",
|
||||
"fill": "#f4f4f4",
|
||||
"border": "#303030",
|
||||
"text": "Text",
|
||||
"size": {
|
||||
"width": 128.0,
|
||||
"height": 128.0
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"cornerRadius": 5.0,
|
||||
"fill": "#f4f4f4",
|
||||
"height": 64.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#303030",
|
||||
"type": "rectangle",
|
||||
"width": 64.0,
|
||||
"x": 32.0,
|
||||
"y": 32.0
|
||||
},
|
||||
{
|
||||
"fill": "none",
|
||||
"height": 48.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#00007f",
|
||||
"type": "line",
|
||||
"width": 0.0,
|
||||
"x": 40.0,
|
||||
"y": 40.0
|
||||
},
|
||||
{
|
||||
"fill": "none",
|
||||
"height": 0.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#00007f",
|
||||
"type": "line",
|
||||
"width": 48.0,
|
||||
"x": 40.0,
|
||||
"y": 88.0
|
||||
},
|
||||
{
|
||||
"fill": "none",
|
||||
"height": 0.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.0,
|
||||
"stroke": "#ffaa00",
|
||||
"type": "line",
|
||||
"width": 48.0,
|
||||
"x": 40.0,
|
||||
"y": 64.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"showName": true
|
||||
},
|
||||
"library": {
|
||||
"showSubtree": true
|
||||
},
|
||||
"implementation": {
|
||||
"kind": "text",
|
||||
"source": {
|
||||
"equations": "y = v+sin(10*time);",
|
||||
"declarations": "",
|
||||
"initialEquations": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "43f739a0-e50f-44ae-bd95-0e0c1a10d1cf",
|
||||
"name": "gain1",
|
||||
"position": {
|
||||
"x": -32.0,
|
||||
"y": -32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"interface": {
|
||||
"inputs": [
|
||||
{
|
||||
"id": "port-df34ce84",
|
||||
"name": "u",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"properties": {
|
||||
"iconPosition": {
|
||||
"x": 64.0,
|
||||
"y": 64.0
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "port-fe9e6486",
|
||||
"name": "y",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"properties": {
|
||||
"iconPosition": {
|
||||
"x": 88.0,
|
||||
"y": 40.0
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"id": "parameter-61a43a86",
|
||||
"name": "k",
|
||||
"type": "real",
|
||||
"value": "-5"
|
||||
}
|
||||
],
|
||||
"icon": {
|
||||
"shape": "rectangle",
|
||||
"fill": "#f4f4f4",
|
||||
"border": "#303030",
|
||||
"text": "Text",
|
||||
"size": {
|
||||
"width": 128.0,
|
||||
"height": 128.0
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"cornerRadius": 5.0,
|
||||
"fill": "#f4f4f4",
|
||||
"height": 64.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#303030",
|
||||
"type": "rectangle",
|
||||
"width": 64.0,
|
||||
"x": 32.0,
|
||||
"y": 32.0
|
||||
},
|
||||
{
|
||||
"color": "#00007f",
|
||||
"fill": "#ffffff",
|
||||
"fontSize": 24.0,
|
||||
"height": 48.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#00007f",
|
||||
"text": "K",
|
||||
"type": "text",
|
||||
"width": 48.0,
|
||||
"x": 40.0,
|
||||
"y": 40.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"showName": true
|
||||
},
|
||||
"library": {
|
||||
"showSubtree": true
|
||||
},
|
||||
"implementation": {
|
||||
"kind": "text",
|
||||
"source": {
|
||||
"equations": "y = k*u;",
|
||||
"declarations": "",
|
||||
"initialEquations": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "59bb51be-8185-4b0b-a894-e38db61aff18",
|
||||
"name": "add0",
|
||||
"position": {
|
||||
"x": 96.0,
|
||||
"y": -96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"interface": {
|
||||
"inputs": [
|
||||
{
|
||||
"id": "port-c995845c",
|
||||
"name": "u",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"properties": {
|
||||
"iconPosition": {
|
||||
"x": 64.0,
|
||||
"y": 64.0
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": true
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "port-a2f0dea6",
|
||||
"name": "y",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"properties": {
|
||||
"iconPosition": {
|
||||
"x": 80.0,
|
||||
"y": 48.0
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"parameters": [],
|
||||
"icon": {
|
||||
"shape": "rectangle",
|
||||
"fill": "#f4f4f4",
|
||||
"border": "#303030",
|
||||
"text": "Text",
|
||||
"size": {
|
||||
"width": 128.0,
|
||||
"height": 128.0
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"fill": "#f4f4f4",
|
||||
"height": 48.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#303030",
|
||||
"type": "circle",
|
||||
"width": 48.0,
|
||||
"x": 40.0,
|
||||
"y": 40.0
|
||||
},
|
||||
{
|
||||
"color": "#00007f",
|
||||
"fill": "none",
|
||||
"fontSize": 18.0,
|
||||
"height": 32.0,
|
||||
"lineStyle": "none",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#00007f",
|
||||
"text": "+",
|
||||
"type": "text",
|
||||
"width": 32.0,
|
||||
"x": 48.0,
|
||||
"y": 48.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"showName": false
|
||||
},
|
||||
"library": {
|
||||
"showSubtree": true
|
||||
},
|
||||
"implementation": {
|
||||
"kind": "text",
|
||||
"source": {
|
||||
"equations": "y = sum(u[i] for i in 1:$u_N$ );",
|
||||
"declarations": "",
|
||||
"initialEquations": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "78c8fcb6-bd46-4b85-aa91-3276a8d1e8cb",
|
||||
"name": "Integrate0",
|
||||
"position": {
|
||||
"x": 224.0,
|
||||
"y": -96.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"interface": {
|
||||
"inputs": [
|
||||
{
|
||||
"id": "port-df34ce84",
|
||||
"name": "u",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"properties": {
|
||||
"iconPosition": {
|
||||
"x": 64.0,
|
||||
"y": 64.0
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "port-fe9e6486",
|
||||
"name": "y",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"properties": {
|
||||
"iconPosition": {
|
||||
"x": 88.0,
|
||||
"y": 40.0
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"id": "parameter-61a43a86",
|
||||
"name": "y_start",
|
||||
"type": "real",
|
||||
"value": "0"
|
||||
}
|
||||
],
|
||||
"icon": {
|
||||
"shape": "rectangle",
|
||||
"fill": "#f4f4f4",
|
||||
"border": "#303030",
|
||||
"text": "Text",
|
||||
"size": {
|
||||
"width": 128.0,
|
||||
"height": 128.0
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"cornerRadius": 5.0,
|
||||
"fill": "#f4f4f4",
|
||||
"height": 64.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#303030",
|
||||
"type": "rectangle",
|
||||
"width": 64.0,
|
||||
"x": 32.0,
|
||||
"y": 32.0
|
||||
},
|
||||
{
|
||||
"color": "#00007f",
|
||||
"fill": "#ffffff",
|
||||
"fontSize": 24.0,
|
||||
"height": 48.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#00007f",
|
||||
"text": "dt",
|
||||
"type": "text",
|
||||
"width": 48.0,
|
||||
"x": 48.0,
|
||||
"y": 40.0
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"x": 32.0,
|
||||
"y": 32.0,
|
||||
"width": 32.0,
|
||||
"height": 56.0,
|
||||
"fill": "none",
|
||||
"stroke": "#00007f",
|
||||
"lineWidth": 1.5,
|
||||
"lineStyle": "none",
|
||||
"text": "\u222b",
|
||||
"fontSize": 35.0,
|
||||
"color": "#00007f"
|
||||
}
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"showName": true
|
||||
},
|
||||
"library": {
|
||||
"showSubtree": true
|
||||
},
|
||||
"implementation": {
|
||||
"kind": "text",
|
||||
"source": {
|
||||
"equations": "der(y) = u;",
|
||||
"declarations": "",
|
||||
"initialEquations": "y = y_start;"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "f2caf59f-5688-46b4-b17d-bdc911580d7b",
|
||||
"name": "Differentiate0",
|
||||
"position": {
|
||||
"x": 224.0,
|
||||
"y": 32.0
|
||||
},
|
||||
"rotation": 0.0,
|
||||
"interface": {
|
||||
"inputs": [
|
||||
{
|
||||
"id": "port-df34ce84",
|
||||
"name": "u",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"properties": {
|
||||
"iconPosition": {
|
||||
"x": 64.0,
|
||||
"y": 64.0
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "port-fe9e6486",
|
||||
"name": "y",
|
||||
"position": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"properties": {
|
||||
"iconPosition": {
|
||||
"x": 88.0,
|
||||
"y": 40.0
|
||||
}
|
||||
},
|
||||
"type": "signal",
|
||||
"multipleConnections": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"id": "parameter-61a43a86",
|
||||
"name": "x_start",
|
||||
"type": "real",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"id": "parameter-d110667b",
|
||||
"name": "y_start",
|
||||
"type": "real",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"id": "parameter-873b503d",
|
||||
"name": "k",
|
||||
"type": "real",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"id": "parameter-a55752c7",
|
||||
"name": "T",
|
||||
"type": "real",
|
||||
"value": "0.01"
|
||||
}
|
||||
],
|
||||
"icon": {
|
||||
"shape": "rectangle",
|
||||
"fill": "#f4f4f4",
|
||||
"border": "#303030",
|
||||
"text": "Text",
|
||||
"size": {
|
||||
"width": 128.0,
|
||||
"height": 128.0
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"cornerRadius": 5.0,
|
||||
"fill": "#f4f4f4",
|
||||
"height": 64.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#303030",
|
||||
"type": "rectangle",
|
||||
"width": 64.0,
|
||||
"x": 32.0,
|
||||
"y": 32.0
|
||||
},
|
||||
{
|
||||
"color": "#00007f",
|
||||
"fill": "#ffffff",
|
||||
"fontSize": 22.0,
|
||||
"height": 48.0,
|
||||
"lineStyle": "solid",
|
||||
"lineWidth": 1.5,
|
||||
"stroke": "#00007f",
|
||||
"text": "d/dt",
|
||||
"type": "text",
|
||||
"width": 64.0,
|
||||
"x": 32.0,
|
||||
"y": 40.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"showName": true
|
||||
},
|
||||
"library": {
|
||||
"showSubtree": true
|
||||
},
|
||||
"implementation": {
|
||||
"kind": "text",
|
||||
"source": {
|
||||
"equations": "assert(T > 0, \"Differentiate time constant T must be positive\");\n\nder(x) = (u - x)/T;\ny = (k/T)*(u - x);",
|
||||
"declarations": "Real x(start=x_start);",
|
||||
"initialEquations": "y = y_start;"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"id": "df23ff13-2a30-4c85-be66-56f66114d58e",
|
||||
"id": "5582d4ad-7c7a-40fe-87d2-9b78410336b3",
|
||||
"source": {
|
||||
"block": "2e6a192c-5aeb-45d6-80ee-d64a72392b76",
|
||||
"block": "86ba2bf6-0da5-40a4-98e9-fb0d9c12c576",
|
||||
"port": "port-ddc97277"
|
||||
},
|
||||
"target": {
|
||||
"block": "f4a78255-8b73-4bb3-ae8e-24b566c72bc0",
|
||||
"block": "7805cb2f-c938-44b2-a1f8-e1b4af13f7bf",
|
||||
"port": "port-df34ce84"
|
||||
},
|
||||
"name": "",
|
||||
"properties": {
|
||||
"waypoints": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "00f7d291-641b-4200-afa3-f1ec941faed7",
|
||||
"source": {
|
||||
"block": "0b29c706-eb1b-4839-8ad2-bbed64efc01e",
|
||||
"port": "port-ddc97277"
|
||||
},
|
||||
"target": {
|
||||
"block": "43f739a0-e50f-44ae-bd95-0e0c1a10d1cf",
|
||||
"port": "port-df34ce84"
|
||||
},
|
||||
"name": "",
|
||||
"properties": {
|
||||
"waypoints": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7a776aab-deb5-4e50-838e-b6b4635f349c",
|
||||
"source": {
|
||||
"block": "f4a78255-8b73-4bb3-ae8e-24b566c72bc0",
|
||||
"port": "port-fe9e6486"
|
||||
},
|
||||
"target": {
|
||||
"block": "59bb51be-8185-4b0b-a894-e38db61aff18",
|
||||
"port": "port-c995845c"
|
||||
},
|
||||
"name": "",
|
||||
"properties": {
|
||||
"waypoints": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5b3d71c3-282a-4c2d-85f8-b92bba5bf2df",
|
||||
"source": {
|
||||
"block": "43f739a0-e50f-44ae-bd95-0e0c1a10d1cf",
|
||||
"port": "port-fe9e6486"
|
||||
},
|
||||
"target": {
|
||||
"block": "59bb51be-8185-4b0b-a894-e38db61aff18",
|
||||
"port": "port-c995845c"
|
||||
},
|
||||
"name": "",
|
||||
"properties": {
|
||||
"waypoints": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "33e15cc2-7f33-469e-91a8-921c04f6b823",
|
||||
"source": {
|
||||
"block": "59bb51be-8185-4b0b-a894-e38db61aff18",
|
||||
"port": "port-a2f0dea6"
|
||||
},
|
||||
"target": {
|
||||
"block": "78c8fcb6-bd46-4b85-aa91-3276a8d1e8cb",
|
||||
"port": "port-df34ce84"
|
||||
},
|
||||
"name": "",
|
||||
"properties": {
|
||||
"waypoints": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "26e10b34-f168-4492-b4f2-fb46d8a4aafa",
|
||||
"source": {
|
||||
"block": "59bb51be-8185-4b0b-a894-e38db61aff18",
|
||||
"port": "port-a2f0dea6"
|
||||
},
|
||||
"target": {
|
||||
"block": "f2caf59f-5688-46b4-b17d-bdc911580d7b",
|
||||
"port": "port-df34ce84"
|
||||
},
|
||||
"name": "",
|
||||
"properties": {
|
||||
"waypoints": [
|
||||
{
|
||||
"x": 160.0,
|
||||
"y": 96.0
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"annotations": [],
|
||||
"junctions": [],
|
||||
"simulation": {
|
||||
"enabled": false,
|
||||
"startTime": 0.0,
|
||||
"stopTime": 10.0,
|
||||
"intervalMode": "intervalTime",
|
||||
"numberOfIntervals": 50000,
|
||||
"intervalTime": 0.002
|
||||
}
|
||||
"simulation": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user