diff --git a/BEdit/.vscode/tasks.json b/BEdit/.vscode/tasks.json
index 82b7b37..12e8f76 100644
--- a/BEdit/.vscode/tasks.json
+++ b/BEdit/.vscode/tasks.json
@@ -48,7 +48,7 @@
"args": [
"${workspaceFolder}/resources/resources.qrc",
"-o",
- "${workspaceFolder}/src/bedit/resources_rc.py"
+ "${workspaceFolder}/src/bedit/gui/generated/resources_rc.py"
],
"options": {
"cwd": "${workspaceFolder}"
@@ -68,7 +68,7 @@
"--from-imports",
"${workspaceFolder}/ui/main_window.ui",
"-o",
- "${workspaceFolder}/src/bedit/ui_main_window.py"
+ "${workspaceFolder}/src/bedit/gui/generated/ui_main_window.py"
],
"options": {
"cwd": "${workspaceFolder}"
@@ -87,7 +87,7 @@
"--from-imports",
"${workspaceFolder}/ui/settings_dialog.ui",
"-o",
- "${workspaceFolder}/src/bedit/ui_settings_dialog.py"
+ "${workspaceFolder}/src/bedit/gui/generated/ui_settings_dialog.py"
],
"options": {
"cwd": "${workspaceFolder}"
@@ -106,7 +106,7 @@
"--from-imports",
"${workspaceFolder}/ui/component_options_dialog.ui",
"-o",
- "${workspaceFolder}/src/bedit/ui_component_options_dialog.py"
+ "${workspaceFolder}/src/bedit/gui/generated/ui_component_options_dialog.py"
],
"options": {"cwd": "${workspaceFolder}"},
"problemMatcher": [],
diff --git a/BEdit/AGENTS.md b/BEdit/AGENTS.md
new file mode 100644
index 0000000..0af9c71
--- /dev/null
+++ b/BEdit/AGENTS.md
@@ -0,0 +1,194 @@
+# AGENTS.md
+
+This file is the working guide for AI coding agents contributing to BEdit.
+Its instructions apply to the entire repository.
+
+## Project purpose
+
+BEdit is a Python/PySide6 graphical editor for hierarchical block and bond-graph
+models. A document contains reusable components, typed and oriented ports,
+connections, nested graphs, and editable vector icons.
+
+The application is evolving quickly. Prefer small, coherent changes that improve
+the architecture without introducing compatibility layers unless compatibility is
+explicitly requested.
+
+## Architecture
+
+The main boundary is strict:
+
+```text
+src/bedit/
+├── __main__.py
+├── core/ # Pure Python; must not import PySide6
+│ ├── model.py # Document, component, graph, port, icon data
+│ ├── port_types.py # Port type definitions and compatibility
+│ ├── serializer.py # JSON persistence
+│ └── libraries.py # Library file discovery and parsing
+└── gui/ # All Qt-dependent code
+ ├── app.py # QApplication startup and palette
+ ├── main_window.py # Top-level UI orchestration
+ ├── preferences.py # Explicit disk-backed QSettings factory
+ ├── controllers/ # Document controller and undo commands
+ ├── dialogs/ # Dialog behavior
+ ├── graphics/ # Workspace, icon editor, vector rendering
+ ├── models/ # Qt tree models and repository adapters
+ └── generated/ # Generated UI/resource Python; never hand-edit
+```
+
+Dependency direction:
+
+- `bedit.core` may depend only on the Python standard library.
+- `bedit.gui` may depend on `bedit.core` and PySide6.
+- `bedit.core` must never import `bedit.gui` or PySide6.
+- Data parsing and validation belong in `core`.
+- Signals, widgets, painting, Qt models, undo integration, and settings UI belong
+ in `gui`.
+
+Keep the root of `src/bedit` minimal. New UI modules should go into the relevant
+`gui` subpackage rather than the package root.
+
+## Important behavior and design decisions
+
+- Components may contain nested graph or text implementations.
+- Ports retain stable IDs. Display names, types, orientation, positions, and icon
+ anchors may change without changing IDs.
+- Port orientation is presented as one unified list in the UI, while the model
+ 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 removal or reorientation must be rejected when it would invalidate an
+ existing connection.
+- Connections reference port IDs, never port names.
+- Icon editing uses a fixed 128×128 coordinate space.
+- The visible/selectable component hitbox is calculated from vector elements,
+ not from the complete 128×128 icon canvas.
+- New component icons default to a centered 64×64 shape.
+- Vector elements include rectangles, circles, ellipses, lines, triangles, and
+ text. Shape styling and geometry are stored in document JSON.
+- Icon port anchors are stored in `Port.properties["iconPosition"]`.
+- Workspace grid size, workspace snapping size, and icon grid size are separate
+ persisted settings.
+- Settings use `gui.preferences.application_settings()` and are stored under the
+ explicit `BEdit/BEdit` identity. Do not create anonymous `QSettings()` objects.
+- Avoid the QSettings group name `general`; Qt treats `General` specially in INI
+ files. Autosave keys live under `autosave/`.
+- User-visible document edits should participate in undo/redo.
+
+## Qt Designer and generated files
+
+Editable Designer sources are in `ui/`. Resources are defined in
+`resources/resources.qrc`.
+
+Never hand-edit files in `src/bedit/gui/generated/`. Modify the corresponding
+`.ui` or `.qrc` source and regenerate instead.
+
+Use the configured VS Code task **Qt: Build Designer Files**, or run the relevant
+commands directly:
+
+```bash
+pyside6-rcc resources/resources.qrc \
+ -o src/bedit/gui/generated/resources_rc.py
+
+pyside6-uic --from-imports ui/main_window.ui \
+ -o src/bedit/gui/generated/ui_main_window.py
+
+pyside6-uic --from-imports ui/settings_dialog.ui \
+ -o src/bedit/gui/generated/ui_settings_dialog.py
+
+pyside6-uic --from-imports ui/component_options_dialog.ui \
+ -o src/bedit/gui/generated/ui_component_options_dialog.py
+```
+
+When adding a promoted/custom widget in Designer, its header must use the real
+Python module path, for example `bedit.gui.graphics.workspace`.
+
+Some dialogs are currently assembled programmatically. Keep that code inside
+`gui/dialogs`; do not put widget creation in `core`.
+
+## Editing conventions
+
+- Preserve stable document IDs and existing connections.
+- Validate candidate document changes before pushing an undo command.
+- Keep model serialization symmetrical: additions to `to_dict()` require matching
+ handling in `from_dict()` and cloning where relevant.
+- Use descriptive domain names; avoid generic `utils.py` modules.
+- Prefer focused classes and helpers over growing `main_window.py` further.
+- Shared vector calculations that do not require Qt belong in `core`; Qt painter
+ code belongs in `gui/graphics`.
+- Do not silently swallow malformed document data. Raise a useful `ValueError` in
+ `core`, then present it through the GUI layer.
+- Preserve unrelated user changes. The worktree may already be dirty.
+- Do not delete or overwrite library/document JSON unless the requested workflow
+ explicitly calls for it.
+
+## Document and library files
+
+- Documents use the `bedit-document` JSON format.
+- `test.bedit.json` is a useful manually created example during development.
+- Library documents use the same recursive document model.
+- Library parsing belongs in `core/libraries.py`; Qt change notifications belong
+ in `gui/models/library_repository.py`.
+- Package library data, if present, belongs under `src/bedit/data/libraries/`.
+
+## Validation
+
+There is not yet a complete automated test suite. For every change, run at least:
+
+```bash
+python3 -m compileall -q src
+git diff --check
+```
+
+Run imports with the source tree explicitly available:
+
+```bash
+PYTHONPATH=src python3 -c "import bedit.core; import bedit.gui.app"
+```
+
+Verify the backend remains Qt-free after core changes:
+
+```bash
+PYTHONPATH=src python3 - <<'PY'
+import sys
+import bedit.core
+assert not any(name.startswith("PySide6") for name in sys.modules)
+PY
+```
+
+For model changes, add a focused in-memory round-trip check using
+`GraphDocument.to_dict()` and `GraphDocument.from_dict()`. For controller changes,
+exercise undo and redo when applicable.
+
+GUI smoke tests may fail in headless environments because the system Qt platform
+theme tries to access a display even with an offscreen platform. Do not claim an
+interactive GUI test passed unless a display-capable environment was actually
+used. Compilation, imports, and pure model/controller checks remain useful.
+
+If Ruff is installed, also run:
+
+```bash
+ruff check src
+```
+
+## Running the application
+
+Install the package in editable mode or run it from the source tree:
+
+```bash
+PYTHONPATH=src python3 -m bedit
+```
+
+The installed GUI entry point is `bedit.gui.app:main`.
+
+## Completion checklist
+
+Before handing off a change:
+
+1. Confirm the `core`/`gui` dependency boundary is intact.
+2. Confirm generated files were not hand-edited.
+3. Check serialization and cloning for model changes.
+4. Check undo/redo for document mutations.
+5. Run compilation and `git diff --check`.
+6. Report any GUI behavior that could not be tested interactively.
+7. Update README or this file if the architecture or workflow changed.
diff --git a/BEdit/README.md b/BEdit/README.md
index 7c09107..9bdd555 100644
--- a/BEdit/README.md
+++ b/BEdit/README.md
@@ -36,12 +36,18 @@ After installation, the `bedit` command also launches the application.
.
├── pyproject.toml dependencies, package metadata, and `bedit` command
├── README.md
-├── ui/main_window.ui editable Qt Designer source
+├── ui/ editable Qt Designer sources
└── src/bedit
- ├── __main__.py supports `python -m bedit`
- ├── app.py starts Qt and applies the forced light palette
- ├── main_window.py behavior and signal connections
- └── ui_main_window.py generated from the Designer file; do not hand-edit
+ ├── __main__.py minimal `python -m bedit` entry point
+ ├── core/ Qt-free domain model, port types, files, libraries
+ └── gui/ every PySide-dependent module
+ ├── app.py Qt startup and application palette
+ ├── main_window.py top-level UI orchestration
+ ├── controllers/ document controller and undo commands
+ ├── dialogs/ dialog behavior
+ ├── graphics/ graph workspace and vector icon editor
+ ├── models/ Qt tree models and repository adapters
+ └── generated/ generated UI/resources; do not hand-edit
```
## Designing the UI further
@@ -61,11 +67,12 @@ Save the form, close the running application if necessary, then regenerate its
Python wrapper:
```bash
-pyside6-uic ui/main_window.ui -o src/bedit/ui_main_window.py
+pyside6-uic --from-imports ui/main_window.ui \
+ -o src/bedit/gui/generated/ui_main_window.py
```
-Do not hand-edit the generated Python file; change the `.ui` file and regenerate
-it. Add behavior and signal connections in `main_window.py`. Widget names from
+Do not hand-edit files in `gui/generated`; change the `.ui` source and regenerate
+it. Add behavior and signal connections in `gui/main_window.py`. Widget names from
Designer are available there through `self.ui`, such as `self.ui.graphView`.
In VS Code, the same commands are available through **Terminal → Run Task**:
@@ -76,16 +83,13 @@ In VS Code, the same commands are available through **Terminal → Run Task**:
- The separate resource and UI compilation tasks remain available when only one
generated file needs rebuilding.
-## A sensible next design pass
+## Architecture rules
-1. Sketch the main tasks and screens before choosing widgets.
-2. Turn each major area into its own widget class in `src/bedit/widgets/`.
-3. Use a `QStackedWidget` for page-like navigation, or `QDockWidget` for movable
- tool panels in an editor-style application.
-4. Use reusable `QAction` objects for menu commands and any future toolbars.
-5. Keep file/data operations outside widget classes as the application grows.
-6. Add icons through a Qt resource file (`.qrc`) so packaging is reliable.
-7. Test on Windows regularly; fonts, scaling, and native dialogs vary by platform.
+- `bedit.core` must remain importable without PySide6.
+- `bedit.gui` may depend on `core`; `core` must never import `gui`.
+- Designer output and resource output belong only in `gui/generated`.
+- Domain serialization and library parsing stay in `core`; Qt signals, models,
+ undo integration, painting, and widgets stay in `gui`.
## Graph and library prototype
@@ -170,10 +174,9 @@ lines, triangles, and text. Each element owns its geometry, fill, stroke, and
line style; ports keep their icon anchor in `properties.iconPosition`. The
port type registry controls which types may connect (currently `signal` only).
The workspace grid size, its finer snapping size, and the icon grid size are
-configured independently in Settings. The
-recursive model is under `src/bedit/document/`, library loading
-and the live Current Document tree are under `src/bedit/library/`, and graphics
-are isolated under `src/bedit/workspace/`.
+configured independently in Settings. The recursive model and file loading are
+under `src/bedit/core/`; the live Qt trees and graphics are isolated under
+`src/bedit/gui/models/` and `src/bedit/gui/graphics/`.
## Optional tools
diff --git a/BEdit/data/libraries/test.bedit.json b/BEdit/data/libraries/test.bedit.json
deleted file mode 100644
index a79b1f5..0000000
--- a/BEdit/data/libraries/test.bedit.json
+++ /dev/null
@@ -1,162 +0,0 @@
-{
- "format": "bedit-document",
- "version": 1,
- "metadata": {
- "name": "Untitled"
- },
- "roots": [
- {
- "id": "5ee742db-b25c-4d86-b4ca-cc0e61c4002a",
- "name": "New Graph Block 1",
- "position": {
- "x": 0.0,
- "y": 0.0
- },
- "rotation": 0.0,
- "interface": {
- "inputs": [],
- "outputs": []
- },
- "icon": {
- "shape": "rectangle",
- "fill": "#f4f4f4",
- "border": "#303030",
- "text": "Graph",
- "size": {
- "width": 128.0,
- "height": 128.0
- },
- "elements": [
- {
- "type": "rectangle",
- "x": 1.0,
- "y": 1.0,
- "width": 126.0,
- "height": 126.0,
- "fill": "#f4f4f4",
- "stroke": "#303030",
- "lineWidth": 1.5,
- "lineStyle": "solid",
- "cornerRadius": 5.0
- },
- {
- "type": "text",
- "x": 8.0,
- "y": 8.0,
- "width": 112.0,
- "height": 112.0,
- "text": "Graph",
- "color": "#202020",
- "fontSize": 12.0
- }
- ]
- },
- "properties": {},
- "library": {
- "showSubtree": true
- },
- "implementation": {
- "kind": "graph",
- "graph": {
- "blocks": [
- {
- "id": "89944479-e73e-446a-8d58-ebf35ac4144b",
- "name": "New Graph Block 1",
- "position": {
- "x": 0.0,
- "y": -96.0
- },
- "rotation": 0.0,
- "interface": {
- "inputs": [
- {
- "id": "port-e5cb81a5",
- "name": "Port 1",
- "position": {
- "x": 0.0,
- "y": 0.0
- },
- "properties": {
- "iconPosition": {
- "x": 32.0,
- "y": 64.0
- }
- },
- "type": "signal"
- }
- ],
- "outputs": [
- {
- "id": "port-eb0034af",
- "name": "Port 2",
- "position": {
- "x": 0.0,
- "y": 0.0
- },
- "properties": {
- "iconPosition": {
- "x": 96.0,
- "y": 64.0
- }
- },
- "type": "signal"
- }
- ]
- },
- "icon": {
- "shape": "rectangle",
- "fill": "#f4f4f4",
- "border": "#303030",
- "text": "Graph",
- "size": {
- "width": 128.0,
- "height": 128.0
- },
- "elements": [
- {
- "type": "rectangle",
- "x": 32.0,
- "y": 32.0,
- "width": 64.0,
- "height": 64.0,
- "fill": "#f4f4f4",
- "stroke": "#303030",
- "lineWidth": 1.5,
- "lineStyle": "solid",
- "cornerRadius": 5.0
- },
- {
- "type": "text",
- "x": 40.0,
- "y": 40.0,
- "width": 48.0,
- "height": 48.0,
- "text": "Graph",
- "color": "#303030",
- "fontSize": 12.0,
- "lineStyle": "solid",
- "lineWidth": 1.5,
- "stroke": "#303030",
- "fill": "#ffffff"
- }
- ]
- },
- "properties": {},
- "library": {
- "showSubtree": true
- },
- "implementation": {
- "kind": "graph",
- "graph": {
- "blocks": [],
- "connections": []
- }
- }
- }
- ],
- "connections": []
- }
- }
- }
- ]
-}
diff --git a/BEdit/pyproject.toml b/BEdit/pyproject.toml
index dda8867..58f9e45 100644
--- a/BEdit/pyproject.toml
+++ b/BEdit/pyproject.toml
@@ -19,7 +19,7 @@ dev = [
]
[project.gui-scripts]
-bedit = "bedit.app:main"
+bedit = "bedit.gui.app:main"
[tool.setuptools.packages.find]
where = ["src"]
diff --git a/BEdit/src/bedit/__main__.py b/BEdit/src/bedit/__main__.py
index 5127970..e338300 100644
--- a/BEdit/src/bedit/__main__.py
+++ b/BEdit/src/bedit/__main__.py
@@ -1,6 +1,5 @@
-from bedit.app import main
+from bedit.gui.app import main
if __name__ == "__main__":
raise SystemExit(main())
-
diff --git a/BEdit/src/bedit/core/__init__.py b/BEdit/src/bedit/core/__init__.py
new file mode 100644
index 0000000..4c8dc39
--- /dev/null
+++ b/BEdit/src/bedit/core/__init__.py
@@ -0,0 +1,5 @@
+"""Pure BEdit domain model and persistence; this package has no Qt dependency."""
+
+from bedit.core.model import Component, Connection, Endpoint, Graph, GraphDocument, Icon, Port
+
+__all__ = ["Component", "Connection", "Endpoint", "Graph", "GraphDocument", "Icon", "Port"]
diff --git a/BEdit/src/bedit/core/libraries.py b/BEdit/src/bedit/core/libraries.py
new file mode 100644
index 0000000..8da3b21
--- /dev/null
+++ b/BEdit/src/bedit/core/libraries.py
@@ -0,0 +1,32 @@
+import json
+from dataclasses import dataclass
+from pathlib import Path
+
+from bedit.core.model import GraphDocument
+
+
+@dataclass(frozen=True)
+class LibraryDocument:
+ name: str
+ document: GraphDocument
+ source_path: str
+
+
+def bundled_library_path() -> Path:
+ return Path(__file__).resolve().parents[1] / "data" / "libraries" / "example.json"
+
+
+def default_library_paths() -> list[str]:
+ return [str(bundled_library_path())]
+
+
+def load_library_file(path: Path) -> LibraryDocument:
+ with path.open(encoding="utf-8") as file:
+ data = json.load(file)
+ document = GraphDocument.from_dict(data)
+ name = str(document.metadata.get("name") or path.stem)
+ return LibraryDocument(name, document, str(path))
+
+
+def library_candidates(path: Path) -> list[Path]:
+ return sorted(path.glob("*.json")) if path.is_dir() else [path]
diff --git a/BEdit/src/bedit/document/model.py b/BEdit/src/bedit/core/model.py
similarity index 99%
rename from BEdit/src/bedit/document/model.py
rename to BEdit/src/bedit/core/model.py
index 6a1d248..758c835 100644
--- a/BEdit/src/bedit/document/model.py
+++ b/BEdit/src/bedit/core/model.py
@@ -5,7 +5,7 @@ from dataclasses import dataclass, field
from typing import Any
from uuid import uuid4
-from bedit.document.port_types import PortTypeRegistry
+from bedit.core.port_types import PortTypeRegistry
@dataclass
diff --git a/BEdit/src/bedit/document/port_types.py b/BEdit/src/bedit/core/port_types.py
similarity index 100%
rename from BEdit/src/bedit/document/port_types.py
rename to BEdit/src/bedit/core/port_types.py
diff --git a/BEdit/src/bedit/document/serializer.py b/BEdit/src/bedit/core/serializer.py
similarity index 93%
rename from BEdit/src/bedit/document/serializer.py
rename to BEdit/src/bedit/core/serializer.py
index b810360..e9e720a 100644
--- a/BEdit/src/bedit/document/serializer.py
+++ b/BEdit/src/bedit/core/serializer.py
@@ -1,7 +1,7 @@
import json
from pathlib import Path
-from bedit.document.model import GraphDocument
+from bedit.core.model import GraphDocument
class JsonDocumentSerializer:
@@ -20,4 +20,3 @@ class JsonDocumentSerializer:
json.dump(document.to_dict(), file, indent=2)
file.write("\n")
temporary_path.replace(path)
-
diff --git a/BEdit/src/bedit/data/libraries/example.json b/BEdit/src/bedit/data/libraries/example.json
new file mode 100644
index 0000000..2b788b4
--- /dev/null
+++ b/BEdit/src/bedit/data/libraries/example.json
@@ -0,0 +1,212 @@
+{
+ "format": "bedit-document",
+ "version": 1,
+ "metadata": {
+ "name": "Example"
+ },
+ "roots": [
+ {
+ "id": "bf714517-e7b2-4f4b-8b53-55642e3beb28",
+ "name": "A",
+ "position": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "rotation": 0.0,
+ "interface": {
+ "inputs": [
+ {
+ "id": "port-5c5d4695",
+ "name": "Port 1",
+ "position": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "properties": {
+ "iconPosition": {
+ "x": 32.0,
+ "y": 64.0
+ }
+ },
+ "type": "signal"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "port-de109124",
+ "name": "Port 2",
+ "position": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "properties": {
+ "iconPosition": {
+ "x": 96.0,
+ "y": 64.0
+ }
+ },
+ "type": "signal"
+ }
+ ]
+ },
+ "icon": {
+ "shape": "rectangle",
+ "fill": "#f4f4f4",
+ "border": "#303030",
+ "text": "Text",
+ "size": {
+ "width": 128.0,
+ "height": 128.0
+ },
+ "elements": [
+ {
+ "type": "rectangle",
+ "x": 32.0,
+ "y": 32.0,
+ "width": 64.0,
+ "height": 64.0,
+ "fill": "#f4f4f4",
+ "stroke": "#303030",
+ "lineWidth": 1.5,
+ "lineStyle": "solid",
+ "cornerRadius": 5.0
+ },
+ {
+ "type": "text",
+ "x": 40.0,
+ "y": 40.0,
+ "width": 48.0,
+ "height": 48.0,
+ "text": "A",
+ "color": "#303030",
+ "fontSize": 12.0,
+ "lineStyle": "solid",
+ "lineWidth": 1.5,
+ "stroke": "#303030",
+ "fill": "#ffffff"
+ }
+ ]
+ },
+ "properties": {},
+ "library": {
+ "showSubtree": true
+ },
+ "implementation": {
+ "kind": "text",
+ "source": {
+ "equations": [],
+ "parameters": {}
+ }
+ }
+ },
+ {
+ "id": "73c9d0c0-293d-4a55-8b89-a1f095dfa75f",
+ "name": "B",
+ "position": {
+ "x": 0.0,
+ "y": 0.0
+ },
+ "rotation": 0.0,
+ "interface": {
+ "inputs": [
+ {
+ "id": "port-4f732b3e",
+ "name": "Port 1",
+ "position": {
+ "x": -176.0,
+ "y": -144.0
+ },
+ "properties": {
+ "iconPosition": {
+ "x": 32.0,
+ "y": 48.0
+ }
+ },
+ "type": "signal"
+ },
+ {
+ "id": "port-ef7c4218",
+ "name": "Port 2",
+ "position": {
+ "x": -176.0,
+ "y": -16.0
+ },
+ "properties": {
+ "iconPosition": {
+ "x": 32.0,
+ "y": 80.0
+ }
+ },
+ "type": "signal"
+ }
+ ],
+ "outputs": [
+ {
+ "id": "port-b68679b2",
+ "name": "Port 3",
+ "position": {
+ "x": 128.0,
+ "y": -80.0
+ },
+ "properties": {
+ "iconPosition": {
+ "x": 96.0,
+ "y": 64.0
+ }
+ },
+ "type": "signal"
+ }
+ ]
+ },
+ "icon": {
+ "shape": "rectangle",
+ "fill": "#f4f4f4",
+ "border": "#303030",
+ "text": "Graph",
+ "size": {
+ "width": 128.0,
+ "height": 128.0
+ },
+ "elements": [
+ {
+ "type": "rectangle",
+ "x": 32.0,
+ "y": 32.0,
+ "width": 64.0,
+ "height": 64.0,
+ "fill": "#f4f4f4",
+ "stroke": "#303030",
+ "lineWidth": 1.5,
+ "lineStyle": "solid",
+ "cornerRadius": 5.0
+ },
+ {
+ "type": "text",
+ "x": 40.0,
+ "y": 40.0,
+ "width": 48.0,
+ "height": 48.0,
+ "text": "B",
+ "color": "#303030",
+ "fontSize": 12.0,
+ "lineStyle": "solid",
+ "lineWidth": 1.5,
+ "stroke": "#303030",
+ "fill": "#ffffff"
+ }
+ ]
+ },
+ "properties": {},
+ "library": {
+ "showSubtree": true
+ },
+ "implementation": {
+ "kind": "graph",
+ "graph": {
+ "blocks": [],
+ "connections": []
+ }
+ }
+ }
+ ]
+}
diff --git a/BEdit/src/bedit/document/__init__.py b/BEdit/src/bedit/document/__init__.py
deleted file mode 100644
index 33fe6a5..0000000
--- a/BEdit/src/bedit/document/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from bedit.document.controller import DocumentController
-from bedit.document.model import Component, Connection, Endpoint, Graph, GraphDocument, Icon, Port
-
-__all__ = [
- "Component",
- "Connection",
- "DocumentController",
- "Endpoint",
- "Graph",
- "GraphDocument",
- "Icon",
- "Port",
-]
diff --git a/BEdit/src/bedit/gui/__init__.py b/BEdit/src/bedit/gui/__init__.py
new file mode 100644
index 0000000..faf6cbd
--- /dev/null
+++ b/BEdit/src/bedit/gui/__init__.py
@@ -0,0 +1 @@
+"""Qt user interface and application adapters."""
diff --git a/BEdit/src/bedit/app.py b/BEdit/src/bedit/gui/app.py
similarity index 97%
rename from BEdit/src/bedit/app.py
rename to BEdit/src/bedit/gui/app.py
index 7d02232..1997f90 100644
--- a/BEdit/src/bedit/app.py
+++ b/BEdit/src/bedit/gui/app.py
@@ -4,7 +4,7 @@ from PySide6.QtCore import QCoreApplication, Qt
from PySide6.QtGui import QColor, QPalette
from PySide6.QtWidgets import QApplication, QStyleFactory
-from bedit.main_window import MainWindow
+from bedit.gui.main_window import MainWindow
def apply_light_theme(app: QApplication) -> None:
diff --git a/BEdit/src/bedit/gui/controllers/__init__.py b/BEdit/src/bedit/gui/controllers/__init__.py
new file mode 100644
index 0000000..1580f20
--- /dev/null
+++ b/BEdit/src/bedit/gui/controllers/__init__.py
@@ -0,0 +1,5 @@
+"""Qt-aware application controllers and undo commands."""
+
+from bedit.gui.controllers.document import DocumentController
+
+__all__ = ["DocumentController"]
diff --git a/BEdit/src/bedit/document/commands.py b/BEdit/src/bedit/gui/controllers/commands.py
similarity index 99%
rename from BEdit/src/bedit/document/commands.py
rename to BEdit/src/bedit/gui/controllers/commands.py
index b3e2122..e428a30 100644
--- a/BEdit/src/bedit/document/commands.py
+++ b/BEdit/src/bedit/gui/controllers/commands.py
@@ -1,7 +1,7 @@
from PySide6.QtCore import QPointF
from PySide6.QtGui import QUndoCommand
-from bedit.document.model import Component, Connection, Port
+from bedit.core.model import Component, Connection, Port
class AddComponentCommand(QUndoCommand):
diff --git a/BEdit/src/bedit/document/controller.py b/BEdit/src/bedit/gui/controllers/document.py
similarity index 99%
rename from BEdit/src/bedit/document/controller.py
rename to BEdit/src/bedit/gui/controllers/document.py
index dccc380..a588dc0 100644
--- a/BEdit/src/bedit/document/controller.py
+++ b/BEdit/src/bedit/gui/controllers/document.py
@@ -5,7 +5,7 @@ from uuid import uuid4
from PySide6.QtCore import QObject, QPointF, Signal
from PySide6.QtGui import QUndoStack
-from bedit.document.commands import (
+from bedit.gui.controllers.commands import (
AddComponentCommand,
AddConnectionCommand,
AddInterfacePortCommand,
@@ -20,7 +20,7 @@ from bedit.document.commands import (
ReplaceSourceCommand,
RotateComponentsCommand,
)
-from bedit.document.model import (
+from bedit.core.model import (
Component,
Connection,
Endpoint,
@@ -29,8 +29,8 @@ from bedit.document.model import (
Port,
clone_component,
)
-from bedit.document.port_types import PortTypeRegistry
-from bedit.document.serializer import JsonDocumentSerializer
+from bedit.core.port_types import PortTypeRegistry
+from bedit.core.serializer import JsonDocumentSerializer
class DocumentController(QObject):
diff --git a/BEdit/src/bedit/gui/dialogs/__init__.py b/BEdit/src/bedit/gui/dialogs/__init__.py
new file mode 100644
index 0000000..2cd21d6
--- /dev/null
+++ b/BEdit/src/bedit/gui/dialogs/__init__.py
@@ -0,0 +1 @@
+"""Application dialogs."""
diff --git a/BEdit/src/bedit/component_options_dialog.py b/BEdit/src/bedit/gui/dialogs/component_options.py
similarity index 90%
rename from BEdit/src/bedit/component_options_dialog.py
rename to BEdit/src/bedit/gui/dialogs/component_options.py
index b1252ef..a3f8a54 100644
--- a/BEdit/src/bedit/component_options_dialog.py
+++ b/BEdit/src/bedit/gui/dialogs/component_options.py
@@ -1,8 +1,8 @@
from PySide6.QtWidgets import QDialog, QMessageBox, QPushButton
-from bedit.document.model import Component
-from bedit.icon_editor import IconEditorDialog
-from bedit.ui_component_options_dialog import Ui_ComponentOptionsDialog
+from bedit.core.model import Component
+from bedit.gui.graphics.icon_editor import IconEditorDialog
+from bedit.gui.generated.ui_component_options_dialog import Ui_ComponentOptionsDialog
class ComponentOptionsDialog(QDialog):
diff --git a/BEdit/src/bedit/item_options_dialog.py b/BEdit/src/bedit/gui/dialogs/item_options.py
similarity index 100%
rename from BEdit/src/bedit/item_options_dialog.py
rename to BEdit/src/bedit/gui/dialogs/item_options.py
diff --git a/BEdit/src/bedit/port_options_dialog.py b/BEdit/src/bedit/gui/dialogs/port_options.py
similarity index 98%
rename from BEdit/src/bedit/port_options_dialog.py
rename to BEdit/src/bedit/gui/dialogs/port_options.py
index d5b3e33..dd8258a 100644
--- a/BEdit/src/bedit/port_options_dialog.py
+++ b/BEdit/src/bedit/gui/dialogs/port_options.py
@@ -19,8 +19,8 @@ from PySide6.QtWidgets import (
QWidget,
)
-from bedit.document.model import Component, Port
-from bedit.document.port_types import PortTypeRegistry
+from bedit.core.model import Component, Port
+from bedit.core.port_types import PortTypeRegistry
PORT_ROLE = Qt.ItemDataRole.UserRole
diff --git a/BEdit/src/bedit/settings_dialog.py b/BEdit/src/bedit/gui/dialogs/settings.py
similarity index 97%
rename from BEdit/src/bedit/settings_dialog.py
rename to BEdit/src/bedit/gui/dialogs/settings.py
index 24708b1..bc367e6 100644
--- a/BEdit/src/bedit/settings_dialog.py
+++ b/BEdit/src/bedit/gui/dialogs/settings.py
@@ -3,9 +3,9 @@ from pathlib import Path
from PySide6.QtCore import QSettings, Signal
from PySide6.QtWidgets import QDialog, QFileDialog, QFormLayout, QGroupBox, QSpinBox
-from bedit.library.repository import default_library_paths
-from bedit.preferences import application_settings
-from bedit.ui_settings_dialog import Ui_SettingsDialog
+from bedit.core.libraries import default_library_paths
+from bedit.gui.preferences import application_settings
+from bedit.gui.generated.ui_settings_dialog import Ui_SettingsDialog
class SettingsDialog(QDialog):
diff --git a/BEdit/src/bedit/gui/generated/__init__.py b/BEdit/src/bedit/gui/generated/__init__.py
new file mode 100644
index 0000000..0a7c1ac
--- /dev/null
+++ b/BEdit/src/bedit/gui/generated/__init__.py
@@ -0,0 +1 @@
+"""Generated Qt code. Do not edit these modules by hand."""
diff --git a/BEdit/src/bedit/resources_rc.py b/BEdit/src/bedit/gui/generated/resources_rc.py
similarity index 100%
rename from BEdit/src/bedit/resources_rc.py
rename to BEdit/src/bedit/gui/generated/resources_rc.py
diff --git a/BEdit/src/bedit/ui_component_options_dialog.py b/BEdit/src/bedit/gui/generated/ui_component_options_dialog.py
similarity index 100%
rename from BEdit/src/bedit/ui_component_options_dialog.py
rename to BEdit/src/bedit/gui/generated/ui_component_options_dialog.py
diff --git a/BEdit/src/bedit/ui_main_window.py b/BEdit/src/bedit/gui/generated/ui_main_window.py
similarity index 99%
rename from BEdit/src/bedit/ui_main_window.py
rename to BEdit/src/bedit/gui/generated/ui_main_window.py
index 1f447f3..38cb3d0 100644
--- a/BEdit/src/bedit/ui_main_window.py
+++ b/BEdit/src/bedit/gui/generated/ui_main_window.py
@@ -22,7 +22,7 @@ from PySide6.QtWidgets import (QApplication, QDockWidget, QFrame, QHBoxLayout,
QSpacerItem, QSplitter, QStackedWidget, QToolBar,
QToolButton, QTreeView, QVBoxLayout, QWidget)
-from bedit.workspace.view import GraphWorkspaceView
+from bedit.gui.graphics.workspace import GraphWorkspaceView
from . import resources_rc
class Ui_MainWindow(object):
diff --git a/BEdit/src/bedit/ui_settings_dialog.py b/BEdit/src/bedit/gui/generated/ui_settings_dialog.py
similarity index 100%
rename from BEdit/src/bedit/ui_settings_dialog.py
rename to BEdit/src/bedit/gui/generated/ui_settings_dialog.py
diff --git a/BEdit/src/bedit/gui/graphics/__init__.py b/BEdit/src/bedit/gui/graphics/__init__.py
new file mode 100644
index 0000000..1c4e281
--- /dev/null
+++ b/BEdit/src/bedit/gui/graphics/__init__.py
@@ -0,0 +1,5 @@
+"""Graphics scenes, views, editors, and renderers."""
+
+from bedit.gui.graphics.workspace import GraphWorkspaceView
+
+__all__ = ["GraphWorkspaceView"]
diff --git a/BEdit/src/bedit/icon_editor.py b/BEdit/src/bedit/gui/graphics/icon_editor.py
similarity index 99%
rename from BEdit/src/bedit/icon_editor.py
rename to BEdit/src/bedit/gui/graphics/icon_editor.py
index 503317e..420b000 100644
--- a/BEdit/src/bedit/icon_editor.py
+++ b/BEdit/src/bedit/gui/graphics/icon_editor.py
@@ -27,9 +27,9 @@ from PySide6.QtWidgets import (
QWidget,
)
-from bedit.document.model import Component, Icon, Port
-from bedit.icon_renderer import _pen
-from bedit.preferences import application_settings
+from bedit.core.model import Component, Icon, Port
+from bedit.gui.graphics.icon_renderer import _pen
+from bedit.gui.preferences import application_settings
def _icon_grid_size() -> int:
diff --git a/BEdit/src/bedit/icon_renderer.py b/BEdit/src/bedit/gui/graphics/icon_renderer.py
similarity index 98%
rename from BEdit/src/bedit/icon_renderer.py
rename to BEdit/src/bedit/gui/graphics/icon_renderer.py
index b260399..84f6f75 100644
--- a/BEdit/src/bedit/icon_renderer.py
+++ b/BEdit/src/bedit/gui/graphics/icon_renderer.py
@@ -1,7 +1,7 @@
from PySide6.QtCore import QPointF, QRectF, Qt
from PySide6.QtGui import QColor, QFont, QIcon, QPainter, QPen, QPixmap, QPolygonF
-from bedit.document.model import Icon
+from bedit.core.model import Icon
def icon_bounds(icon: Icon) -> QRectF:
diff --git a/BEdit/src/bedit/workspace/view.py b/BEdit/src/bedit/gui/graphics/workspace.py
similarity index 98%
rename from BEdit/src/bedit/workspace/view.py
rename to BEdit/src/bedit/gui/graphics/workspace.py
index eea4f8b..398e377 100644
--- a/BEdit/src/bedit/workspace/view.py
+++ b/BEdit/src/bedit/gui/graphics/workspace.py
@@ -28,11 +28,11 @@ from PySide6.QtWidgets import (
QWidget,
)
-from bedit.document.controller import DocumentController
-from bedit.document.model import Component, Connection, Endpoint, Port
-from bedit.library.tree_model import COMPONENT_MIME_TYPE
-from bedit.icon_renderer import icon_bounds, paint_icon
-from bedit.preferences import application_settings
+from bedit.core.model import Component, Connection, Endpoint, Port
+from bedit.gui.controllers.document import DocumentController
+from bedit.gui.models.library_tree import COMPONENT_MIME_TYPE
+from bedit.gui.graphics.icon_renderer import icon_bounds, paint_icon
+from bedit.gui.preferences import application_settings
SELECTION_MIME_TYPE = "application/x-bedit-selection"
diff --git a/BEdit/src/bedit/main_window.py b/BEdit/src/bedit/gui/main_window.py
similarity index 97%
rename from BEdit/src/bedit/main_window.py
rename to BEdit/src/bedit/gui/main_window.py
index bc384ca..e113d62 100644
--- a/BEdit/src/bedit/main_window.py
+++ b/BEdit/src/bedit/gui/main_window.py
@@ -6,23 +6,23 @@ from PySide6.QtCore import QSize, Qt, Slot
from PySide6.QtGui import QAction, QCloseEvent
from PySide6.QtWidgets import QFileDialog, QMainWindow, QMenu, QMessageBox, QToolBar
-from bedit.component_options_dialog import ComponentOptionsDialog
-from bedit.document.controller import DocumentController
-from bedit.document.model import Component, Port
-from bedit.document.serializer import JsonDocumentSerializer
-from bedit.item_options_dialog import ItemOptionsDialog
-from bedit.library.repository import LibraryRepository
-from bedit.library.tree_model import (
+from bedit.core.model import Component, Port
+from bedit.core.serializer import JsonDocumentSerializer
+from bedit.gui.controllers.document import DocumentController
+from bedit.gui.dialogs.component_options import ComponentOptionsDialog
+from bedit.gui.dialogs.item_options import ItemOptionsDialog
+from bedit.gui.models.library_repository import LibraryRepository
+from bedit.gui.models.library_tree import (
COMPONENT_ID_ROLE,
COMPONENT_INSTANCE_ROLE,
ITEM_KIND_ROLE,
DocumentTreeModel,
LibraryTreeModel,
)
-from bedit.settings_dialog import SettingsDialog
-from bedit.port_options_dialog import PortOptionsDialog
-from bedit.preferences import application_settings
-from bedit.ui_main_window import Ui_MainWindow
+from bedit.gui.dialogs.settings import SettingsDialog
+from bedit.gui.dialogs.port_options import PortOptionsDialog
+from bedit.gui.preferences import application_settings
+from bedit.gui.generated.ui_main_window import Ui_MainWindow
class MainWindow(QMainWindow):
diff --git a/BEdit/src/bedit/gui/models/__init__.py b/BEdit/src/bedit/gui/models/__init__.py
new file mode 100644
index 0000000..bd5e1a4
--- /dev/null
+++ b/BEdit/src/bedit/gui/models/__init__.py
@@ -0,0 +1 @@
+"""Qt model/view adapters and repositories."""
diff --git a/BEdit/src/bedit/gui/models/library_repository.py b/BEdit/src/bedit/gui/models/library_repository.py
new file mode 100644
index 0000000..df37009
--- /dev/null
+++ b/BEdit/src/bedit/gui/models/library_repository.py
@@ -0,0 +1,31 @@
+import json
+from pathlib import Path
+
+from PySide6.QtCore import QObject, Signal
+
+from bedit.core.libraries import LibraryDocument, library_candidates, load_library_file
+
+
+class LibraryRepository(QObject):
+ librariesChanged = Signal()
+ loadWarningsChanged = Signal(list)
+
+ def __init__(self, parent=None) -> None:
+ super().__init__(parent)
+ self.libraries: list[LibraryDocument] = []
+ self.load_warnings: list[str] = []
+
+ def load_paths(self, paths: list[str]) -> None:
+ libraries: list[LibraryDocument] = []
+ warnings: list[str] = []
+ for raw_path in paths:
+ path = Path(raw_path).expanduser()
+ for candidate in library_candidates(path):
+ try:
+ libraries.append(load_library_file(candidate))
+ except (OSError, ValueError, KeyError, TypeError, json.JSONDecodeError) as error:
+ warnings.append(f"{candidate}: {error}")
+ self.libraries = libraries
+ self.load_warnings = warnings
+ self.librariesChanged.emit()
+ self.loadWarningsChanged.emit(warnings)
diff --git a/BEdit/src/bedit/library/tree_model.py b/BEdit/src/bedit/gui/models/library_tree.py
similarity index 94%
rename from BEdit/src/bedit/library/tree_model.py
rename to BEdit/src/bedit/gui/models/library_tree.py
index b85e80a..c08fe2d 100644
--- a/BEdit/src/bedit/library/tree_model.py
+++ b/BEdit/src/bedit/gui/models/library_tree.py
@@ -3,10 +3,10 @@ import json
from PySide6.QtCore import QByteArray, QMimeData, QModelIndex, Qt, Signal
from PySide6.QtGui import QStandardItem, QStandardItemModel
-from bedit.document.controller import DocumentController
-from bedit.document.model import Component
-from bedit.icon_renderer import library_icon
-from bedit.library.repository import LibraryRepository
+from bedit.core.model import Component
+from bedit.gui.controllers.document import DocumentController
+from bedit.gui.graphics.icon_renderer import library_icon
+from bedit.gui.models.library_repository import LibraryRepository
COMPONENT_ROLE = Qt.ItemDataRole.UserRole + 1
diff --git a/BEdit/src/bedit/preferences.py b/BEdit/src/bedit/gui/preferences.py
similarity index 100%
rename from BEdit/src/bedit/preferences.py
rename to BEdit/src/bedit/gui/preferences.py
diff --git a/BEdit/src/bedit/library/__init__.py b/BEdit/src/bedit/library/__init__.py
deleted file mode 100644
index a73536b..0000000
--- a/BEdit/src/bedit/library/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from bedit.library.repository import LibraryRepository, default_library_paths
-
-__all__ = ["LibraryRepository", "default_library_paths"]
diff --git a/BEdit/src/bedit/library/repository.py b/BEdit/src/bedit/library/repository.py
deleted file mode 100644
index 448a85a..0000000
--- a/BEdit/src/bedit/library/repository.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import json
-from dataclasses import dataclass
-from pathlib import Path
-
-from PySide6.QtCore import QObject, Signal
-
-from bedit.document.model import GraphDocument
-
-
-@dataclass(frozen=True)
-class LibraryDocument:
- name: str
- document: GraphDocument
- source_path: str
-
-
-def bundled_library_path() -> Path:
- return Path(__file__).resolve().parents[1] / "data" / "libraries" / "example.json"
-
-
-def default_library_paths() -> list[str]:
- return [str(bundled_library_path())]
-
-
-class LibraryRepository(QObject):
- librariesChanged = Signal()
- loadWarningsChanged = Signal(list)
-
- def __init__(self, parent=None) -> None:
- super().__init__(parent)
- self.libraries: list[LibraryDocument] = []
- self.load_warnings: list[str] = []
-
- def load_paths(self, paths: list[str]) -> None:
- libraries: list[LibraryDocument] = []
- warnings: list[str] = []
- for raw_path in paths:
- path = Path(raw_path).expanduser()
- candidates = sorted(path.glob("*.json")) if path.is_dir() else [path]
- for candidate in candidates:
- try:
- libraries.append(self._load_file(candidate))
- except (OSError, ValueError, KeyError, TypeError, json.JSONDecodeError) as error:
- warnings.append(f"{candidate}: {error}")
- self.libraries = libraries
- self.load_warnings = warnings
- self.librariesChanged.emit()
- self.loadWarningsChanged.emit(warnings)
-
- @staticmethod
- def _load_file(path: Path) -> LibraryDocument:
- with path.open(encoding="utf-8") as file:
- data = json.load(file)
- document = GraphDocument.from_dict(data)
- name = str(document.metadata.get("name") or path.stem)
- return LibraryDocument(name, document, str(path))
diff --git a/BEdit/src/bedit/workspace/__init__.py b/BEdit/src/bedit/workspace/__init__.py
deleted file mode 100644
index 72dae2f..0000000
--- a/BEdit/src/bedit/workspace/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from bedit.workspace.view import GraphWorkspaceView
-
-__all__ = ["GraphWorkspaceView"]
-
diff --git a/BEdit/test.bedit.json b/BEdit/test.bedit.json
index a79b1f5..4f2e98f 100644
--- a/BEdit/test.bedit.json
+++ b/BEdit/test.bedit.json
@@ -64,7 +64,7 @@
"name": "New Graph Block 1",
"position": {
"x": 0.0,
- "y": -96.0
+ "y": -64.0
},
"rotation": 0.0,
"interface": {
diff --git a/BEdit/ui/main_window.ui b/BEdit/ui/main_window.ui
index 36b48e3..a4f294c 100644
--- a/BEdit/ui/main_window.ui
+++ b/BEdit/ui/main_window.ui
@@ -484,7 +484,7 @@
GraphWorkspaceView
QGraphicsView
-
+ bedit.gui.graphics.workspace
diff --git a/BEdit/ui/main_window_ui.py b/BEdit/ui/main_window_ui.py
new file mode 100644
index 0000000..1c98bf4
--- /dev/null
+++ b/BEdit/ui/main_window_ui.py
@@ -0,0 +1,450 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'main_window.ui'
+##
+## Created by: Qt User Interface Compiler version 6.11.1
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+ QMetaObject, QObject, QPoint, QRect,
+ QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
+ QCursor, QFont, QFontDatabase, QGradient,
+ QIcon, QImage, QKeySequence, QLinearGradient,
+ QPainter, QPalette, QPixmap, QRadialGradient,
+ QTransform)
+from PySide6.QtWidgets import (QApplication, QDockWidget, QFrame, QHBoxLayout,
+ QHeaderView, QLabel, QMainWindow, QMenu,
+ QMenuBar, QPlainTextEdit, QPushButton, QSizePolicy,
+ QSpacerItem, QSplitter, QStackedWidget, QToolBar,
+ QToolButton, QTreeView, QVBoxLayout, QWidget)
+
+from bedit.gui.graphics.workspace import GraphWorkspaceView
+import resources_rc
+
+class Ui_MainWindow(object):
+ def setupUi(self, MainWindow):
+ if not MainWindow.objectName():
+ MainWindow.setObjectName(u"MainWindow")
+ MainWindow.resize(1000, 700)
+ self.actionNew = QAction(MainWindow)
+ self.actionNew.setObjectName(u"actionNew")
+ icon = QIcon()
+ icon.addFile(u":/icons/icons/document-new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionNew.setIcon(icon)
+ self.actionRotateClockwise = QAction(MainWindow)
+ self.actionRotateClockwise.setObjectName(u"actionRotateClockwise")
+ icon1 = QIcon()
+ icon1.addFile(u":/icons/icons/transform-rotate.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionRotateClockwise.setIcon(icon1)
+ self.actionOpen = QAction(MainWindow)
+ self.actionOpen.setObjectName(u"actionOpen")
+ icon2 = QIcon()
+ icon2.addFile(u":/icons/icons/document-open.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionOpen.setIcon(icon2)
+ self.actionSave = QAction(MainWindow)
+ self.actionSave.setObjectName(u"actionSave")
+ icon3 = QIcon()
+ icon3.addFile(u":/icons/icons/document-save.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionSave.setIcon(icon3)
+ self.actionSaveAs = QAction(MainWindow)
+ self.actionSaveAs.setObjectName(u"actionSaveAs")
+ icon4 = QIcon()
+ icon4.addFile(u":/icons/icons/document-save-as.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionSaveAs.setIcon(icon4)
+ self.actionExit = QAction(MainWindow)
+ self.actionExit.setObjectName(u"actionExit")
+ self.actionClose = QAction(MainWindow)
+ self.actionClose.setObjectName(u"actionClose")
+ self.actionUndo = QAction(MainWindow)
+ self.actionUndo.setObjectName(u"actionUndo")
+ icon5 = QIcon()
+ icon5.addFile(u":/icons/icons/edit-undo.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionUndo.setIcon(icon5)
+ self.actionRedo = QAction(MainWindow)
+ self.actionRedo.setObjectName(u"actionRedo")
+ icon6 = QIcon()
+ icon6.addFile(u":/icons/icons/edit-redo.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionRedo.setIcon(icon6)
+ self.actionCut = QAction(MainWindow)
+ self.actionCut.setObjectName(u"actionCut")
+ icon7 = QIcon()
+ icon7.addFile(u":/icons/icons/edit-cut.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionCut.setIcon(icon7)
+ self.actionCopy = QAction(MainWindow)
+ self.actionCopy.setObjectName(u"actionCopy")
+ icon8 = QIcon()
+ icon8.addFile(u":/icons/icons/edit-copy.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionCopy.setIcon(icon8)
+ self.actionPaste = QAction(MainWindow)
+ self.actionPaste.setObjectName(u"actionPaste")
+ icon9 = QIcon()
+ icon9.addFile(u":/icons/icons/edit-paste.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
+ self.actionPaste.setIcon(icon9)
+ self.actionSelectAll = QAction(MainWindow)
+ self.actionSelectAll.setObjectName(u"actionSelectAll")
+ self.actionDelete = QAction(MainWindow)
+ self.actionDelete.setObjectName(u"actionDelete")
+ self.actionAbout = QAction(MainWindow)
+ self.actionAbout.setObjectName(u"actionAbout")
+ self.actionSettings = QAction(MainWindow)
+ self.actionSettings.setObjectName(u"actionSettings")
+ self.actionAboutQt = QAction(MainWindow)
+ self.actionAboutQt.setObjectName(u"actionAboutQt")
+ self.centralwidget = QWidget(MainWindow)
+ self.centralwidget.setObjectName(u"centralwidget")
+ self.workspaceLayout = QHBoxLayout(self.centralwidget)
+ self.workspaceLayout.setSpacing(0)
+ self.workspaceLayout.setObjectName(u"workspaceLayout")
+ self.workspaceLayout.setContentsMargins(0, 0, 0, 0)
+ self.workspaceSplitter = QSplitter(self.centralwidget)
+ self.workspaceSplitter.setObjectName(u"workspaceSplitter")
+ sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.workspaceSplitter.sizePolicy().hasHeightForWidth())
+ self.workspaceSplitter.setSizePolicy(sizePolicy)
+ self.workspaceSplitter.setOrientation(Qt.Orientation.Horizontal)
+ self.workspaceSplitter.setChildrenCollapsible(False)
+ self.leftDockHost = QMainWindow(self.workspaceSplitter)
+ self.leftDockHost.setObjectName(u"leftDockHost")
+ self.leftDockHost.setMinimumSize(QSize(220, 0))
+ self.panel_libraries = QDockWidget(self.leftDockHost)
+ self.panel_libraries.setObjectName(u"panel_libraries")
+ self.panel_libraries.setMinimumSize(QSize(220, 91))
+ self.dockWidgetContents = QWidget()
+ self.dockWidgetContents.setObjectName(u"dockWidgetContents")
+ self.librariesLayout = QVBoxLayout(self.dockWidgetContents)
+ self.librariesLayout.setSpacing(0)
+ self.librariesLayout.setObjectName(u"librariesLayout")
+ self.librariesLayout.setContentsMargins(0, 0, 0, 0)
+ self.treeView = QTreeView(self.dockWidgetContents)
+ self.treeView.setObjectName(u"treeView")
+ self.treeView.setAlternatingRowColors(True)
+ self.treeView.setUniformRowHeights(True)
+
+ self.librariesLayout.addWidget(self.treeView)
+
+ self.panel_libraries.setWidget(self.dockWidgetContents)
+ self.leftDockHost.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.panel_libraries)
+ self.panel_document = QDockWidget(self.leftDockHost)
+ self.panel_document.setObjectName(u"panel_document")
+ self.panel_document.setMinimumSize(QSize(220, 91))
+ self.documentDockContents = QWidget()
+ self.documentDockContents.setObjectName(u"documentDockContents")
+ self.documentPanelLayout = QVBoxLayout(self.documentDockContents)
+ self.documentPanelLayout.setSpacing(0)
+ self.documentPanelLayout.setObjectName(u"documentPanelLayout")
+ self.documentPanelLayout.setContentsMargins(0, 0, 0, 0)
+ self.documentTreeView = QTreeView(self.documentDockContents)
+ self.documentTreeView.setObjectName(u"documentTreeView")
+ self.documentTreeView.setAlternatingRowColors(True)
+ self.documentTreeView.setUniformRowHeights(True)
+
+ self.documentPanelLayout.addWidget(self.documentTreeView)
+
+ self.panel_document.setWidget(self.documentDockContents)
+ self.leftDockHost.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, self.panel_document)
+ self.workspaceSplitter.addWidget(self.leftDockHost)
+ self.workspace = QWidget(self.workspaceSplitter)
+ self.workspace.setObjectName(u"workspace")
+ sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
+ sizePolicy1.setHorizontalStretch(1)
+ sizePolicy1.setVerticalStretch(0)
+ sizePolicy1.setHeightForWidth(self.workspace.sizePolicy().hasHeightForWidth())
+ self.workspace.setSizePolicy(sizePolicy1)
+ self.workspaceEditorLayout = QVBoxLayout(self.workspace)
+ self.workspaceEditorLayout.setSpacing(0)
+ self.workspaceEditorLayout.setObjectName(u"workspaceEditorLayout")
+ self.workspaceEditorLayout.setContentsMargins(0, 0, 0, 0)
+ self.workspaceHeader = QFrame(self.workspace)
+ self.workspaceHeader.setObjectName(u"workspaceHeader")
+ self.workspaceHeader.setMinimumSize(QSize(0, 34))
+ self.workspaceHeader.setMaximumSize(QSize(16777215, 34))
+ self.workspaceHeader.setFrameShape(QFrame.Shape.StyledPanel)
+ self.workspaceHeaderLayout = QHBoxLayout(self.workspaceHeader)
+ self.workspaceHeaderLayout.setObjectName(u"workspaceHeaderLayout")
+ self.workspaceHeaderLayout.setContentsMargins(6, 2, 6, 2)
+ self.navigateUpButton = QToolButton(self.workspaceHeader)
+ self.navigateUpButton.setObjectName(u"navigateUpButton")
+
+ self.workspaceHeaderLayout.addWidget(self.navigateUpButton)
+
+ self.graphBreadcrumbLabel = QLabel(self.workspaceHeader)
+ self.graphBreadcrumbLabel.setObjectName(u"graphBreadcrumbLabel")
+
+ self.workspaceHeaderLayout.addWidget(self.graphBreadcrumbLabel)
+
+ self.workspaceModeLabel = QLabel(self.workspaceHeader)
+ self.workspaceModeLabel.setObjectName(u"workspaceModeLabel")
+
+ self.workspaceHeaderLayout.addWidget(self.workspaceModeLabel)
+
+ self.workspaceHeaderSpacer = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
+
+ self.workspaceHeaderLayout.addItem(self.workspaceHeaderSpacer)
+
+ self.applyJsonButton = QPushButton(self.workspaceHeader)
+ self.applyJsonButton.setObjectName(u"applyJsonButton")
+ self.applyJsonButton.setVisible(False)
+
+ self.workspaceHeaderLayout.addWidget(self.applyJsonButton)
+
+ self.pointerToolButton = QToolButton(self.workspaceHeader)
+ self.pointerToolButton.setObjectName(u"pointerToolButton")
+ self.pointerToolButton.setCheckable(True)
+ self.pointerToolButton.setChecked(True)
+ self.pointerToolButton.setAutoExclusive(True)
+
+ self.workspaceHeaderLayout.addWidget(self.pointerToolButton)
+
+ self.inputToolButton = QToolButton(self.workspaceHeader)
+ self.inputToolButton.setObjectName(u"inputToolButton")
+ self.inputToolButton.setCheckable(True)
+ self.inputToolButton.setAutoExclusive(True)
+
+ self.workspaceHeaderLayout.addWidget(self.inputToolButton)
+
+ self.outputToolButton = QToolButton(self.workspaceHeader)
+ self.outputToolButton.setObjectName(u"outputToolButton")
+ self.outputToolButton.setCheckable(True)
+ self.outputToolButton.setAutoExclusive(True)
+
+ self.workspaceHeaderLayout.addWidget(self.outputToolButton)
+
+
+ self.workspaceEditorLayout.addWidget(self.workspaceHeader)
+
+ self.workspaceStack = QStackedWidget(self.workspace)
+ self.workspaceStack.setObjectName(u"workspaceStack")
+ self.graphPage = QWidget()
+ self.graphPage.setObjectName(u"graphPage")
+ self.graphPageLayout = QVBoxLayout(self.graphPage)
+ self.graphPageLayout.setObjectName(u"graphPageLayout")
+ self.graphPageLayout.setContentsMargins(0, 0, 0, 0)
+ self.graphView = GraphWorkspaceView(self.graphPage)
+ self.graphView.setObjectName(u"graphView")
+
+ self.graphPageLayout.addWidget(self.graphView)
+
+ self.workspaceStack.addWidget(self.graphPage)
+ self.jsonPage = QWidget()
+ self.jsonPage.setObjectName(u"jsonPage")
+ self.jsonPageLayout = QVBoxLayout(self.jsonPage)
+ self.jsonPageLayout.setObjectName(u"jsonPageLayout")
+ self.jsonPageLayout.setContentsMargins(0, 0, 0, 0)
+ self.jsonEditor = QPlainTextEdit(self.jsonPage)
+ self.jsonEditor.setObjectName(u"jsonEditor")
+ self.jsonEditor.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
+
+ self.jsonPageLayout.addWidget(self.jsonEditor)
+
+ self.workspaceStack.addWidget(self.jsonPage)
+ self.emptyPage = QWidget()
+ self.emptyPage.setObjectName(u"emptyPage")
+ self.emptyPageLayout = QVBoxLayout(self.emptyPage)
+ self.emptyPageLayout.setObjectName(u"emptyPageLayout")
+ self.emptyWorkspaceLabel = QLabel(self.emptyPage)
+ self.emptyWorkspaceLabel.setObjectName(u"emptyWorkspaceLabel")
+ self.emptyWorkspaceLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
+
+ self.emptyPageLayout.addWidget(self.emptyWorkspaceLabel)
+
+ self.workspaceStack.addWidget(self.emptyPage)
+
+ self.workspaceEditorLayout.addWidget(self.workspaceStack)
+
+ self.workspaceSplitter.addWidget(self.workspace)
+
+ self.workspaceLayout.addWidget(self.workspaceSplitter)
+
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QMenuBar(MainWindow)
+ self.menubar.setObjectName(u"menubar")
+ self.menubar.setGeometry(QRect(0, 0, 1000, 24))
+ self.menuFile = QMenu(self.menubar)
+ self.menuFile.setObjectName(u"menuFile")
+ self.menuEdit = QMenu(self.menubar)
+ self.menuEdit.setObjectName(u"menuEdit")
+ self.menuView = QMenu(self.menubar)
+ self.menuView.setObjectName(u"menuView")
+ self.menuPanels = QMenu(self.menuView)
+ self.menuPanels.setObjectName(u"menuPanels")
+ self.menuToolbars = QMenu(self.menuView)
+ self.menuToolbars.setObjectName(u"menuToolbars")
+ self.menuHelp = QMenu(self.menubar)
+ self.menuHelp.setObjectName(u"menuHelp")
+ MainWindow.setMenuBar(self.menubar)
+ self.fileToolbar = QToolBar(MainWindow)
+ self.fileToolbar.setObjectName(u"fileToolbar")
+ sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
+ sizePolicy2.setHorizontalStretch(0)
+ sizePolicy2.setVerticalStretch(0)
+ sizePolicy2.setHeightForWidth(self.fileToolbar.sizePolicy().hasHeightForWidth())
+ self.fileToolbar.setSizePolicy(sizePolicy2)
+ self.fileToolbar.setMinimumSize(QSize(0, 40))
+ self.fileToolbar.setMaximumSize(QSize(16777215, 40))
+ self.fileToolbar.setIconSize(QSize(24, 24))
+ MainWindow.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.fileToolbar)
+ self.editToolbar = QToolBar(MainWindow)
+ self.editToolbar.setObjectName(u"editToolbar")
+ MainWindow.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.editToolbar)
+ self.transformToolbar = QToolBar(MainWindow)
+ self.transformToolbar.setObjectName(u"transformToolbar")
+ MainWindow.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.transformToolbar)
+
+ self.menubar.addAction(self.menuFile.menuAction())
+ self.menubar.addAction(self.menuEdit.menuAction())
+ self.menubar.addAction(self.menuView.menuAction())
+ self.menubar.addAction(self.menuHelp.menuAction())
+ self.menuFile.addAction(self.actionNew)
+ self.menuFile.addAction(self.actionOpen)
+ self.menuFile.addSeparator()
+ self.menuFile.addAction(self.actionSave)
+ self.menuFile.addAction(self.actionSaveAs)
+ self.menuFile.addSeparator()
+ self.menuFile.addAction(self.actionClose)
+ self.menuFile.addAction(self.actionExit)
+ self.menuEdit.addAction(self.actionUndo)
+ self.menuEdit.addAction(self.actionRedo)
+ self.menuEdit.addSeparator()
+ self.menuEdit.addAction(self.actionCopy)
+ self.menuEdit.addAction(self.actionCut)
+ self.menuEdit.addAction(self.actionPaste)
+ self.menuEdit.addAction(self.actionDelete)
+ self.menuEdit.addAction(self.actionSelectAll)
+ self.menuEdit.addSeparator()
+ self.menuEdit.addAction(self.actionSettings)
+ self.menuView.addAction(self.menuPanels.menuAction())
+ self.menuView.addAction(self.menuToolbars.menuAction())
+ self.menuHelp.addAction(self.actionAbout)
+ self.menuHelp.addAction(self.actionAboutQt)
+ self.fileToolbar.addAction(self.actionNew)
+ self.fileToolbar.addAction(self.actionOpen)
+ self.fileToolbar.addAction(self.actionSave)
+ self.fileToolbar.addAction(self.actionSaveAs)
+ self.editToolbar.addAction(self.actionUndo)
+ self.editToolbar.addAction(self.actionRedo)
+ self.editToolbar.addAction(self.actionCopy)
+ self.editToolbar.addAction(self.actionCut)
+ self.editToolbar.addAction(self.actionPaste)
+ self.transformToolbar.addAction(self.actionRotateClockwise)
+
+ self.retranslateUi(MainWindow)
+
+ self.workspaceStack.setCurrentIndex(0)
+
+
+ QMetaObject.connectSlotsByName(MainWindow)
+ # setupUi
+
+ def retranslateUi(self, MainWindow):
+ MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"BEdit", None))
+ self.actionNew.setText(QCoreApplication.translate("MainWindow", u"&New", None))
+#if QT_CONFIG(statustip)
+ self.actionNew.setStatusTip(QCoreApplication.translate("MainWindow", u"Create a new document", None))
+#endif // QT_CONFIG(statustip)
+#if QT_CONFIG(shortcut)
+ self.actionNew.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+N", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionRotateClockwise.setText(QCoreApplication.translate("MainWindow", u"Rotate Clockwise", None))
+#if QT_CONFIG(tooltip)
+ self.actionRotateClockwise.setToolTip(QCoreApplication.translate("MainWindow", u"Rotate selected blocks clockwise by 90 degrees", None))
+#endif // QT_CONFIG(tooltip)
+#if QT_CONFIG(shortcut)
+ self.actionRotateClockwise.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+R", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionOpen.setText(QCoreApplication.translate("MainWindow", u"&Open\u2026", None))
+#if QT_CONFIG(statustip)
+ self.actionOpen.setStatusTip(QCoreApplication.translate("MainWindow", u"Open a document", None))
+#endif // QT_CONFIG(statustip)
+#if QT_CONFIG(shortcut)
+ self.actionOpen.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+O", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionSave.setText(QCoreApplication.translate("MainWindow", u"&Save", None))
+#if QT_CONFIG(statustip)
+ self.actionSave.setStatusTip(QCoreApplication.translate("MainWindow", u"Save the current document", None))
+#endif // QT_CONFIG(statustip)
+#if QT_CONFIG(shortcut)
+ self.actionSave.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+S", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionSaveAs.setText(QCoreApplication.translate("MainWindow", u"Save &As\u2026", None))
+#if QT_CONFIG(shortcut)
+ self.actionSaveAs.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+Shift+S", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionExit.setText(QCoreApplication.translate("MainWindow", u"E&xit", None))
+#if QT_CONFIG(shortcut)
+ self.actionExit.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+Q", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionClose.setText(QCoreApplication.translate("MainWindow", u"&Close Document", None))
+#if QT_CONFIG(shortcut)
+ self.actionClose.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+W", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionUndo.setText(QCoreApplication.translate("MainWindow", u"&Undo", None))
+#if QT_CONFIG(shortcut)
+ self.actionUndo.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+Z", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionRedo.setText(QCoreApplication.translate("MainWindow", u"&Redo", None))
+#if QT_CONFIG(shortcut)
+ self.actionRedo.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+Y", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionCut.setText(QCoreApplication.translate("MainWindow", u"Cu&t", None))
+#if QT_CONFIG(shortcut)
+ self.actionCut.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+X", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionCopy.setText(QCoreApplication.translate("MainWindow", u"&Copy", None))
+#if QT_CONFIG(shortcut)
+ self.actionCopy.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+C", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionPaste.setText(QCoreApplication.translate("MainWindow", u"&Paste", None))
+#if QT_CONFIG(shortcut)
+ self.actionPaste.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+V", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionSelectAll.setText(QCoreApplication.translate("MainWindow", u"Select &All", None))
+#if QT_CONFIG(shortcut)
+ self.actionSelectAll.setShortcut(QCoreApplication.translate("MainWindow", u"Ctrl+A", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionDelete.setText(QCoreApplication.translate("MainWindow", u"&Delete", None))
+#if QT_CONFIG(shortcut)
+ self.actionDelete.setShortcut(QCoreApplication.translate("MainWindow", u"Del", None))
+#endif // QT_CONFIG(shortcut)
+ self.actionAbout.setText(QCoreApplication.translate("MainWindow", u"&About BEdit", None))
+ self.actionSettings.setText(QCoreApplication.translate("MainWindow", u"&Settings\u2026", None))
+#if QT_CONFIG(statustip)
+ self.actionSettings.setStatusTip(QCoreApplication.translate("MainWindow", u"Configure BEdit", None))
+#endif // QT_CONFIG(statustip)
+ self.actionAboutQt.setText(QCoreApplication.translate("MainWindow", u"About &Qt", None))
+ self.panel_libraries.setWindowTitle(QCoreApplication.translate("MainWindow", u"Libraries", None))
+ self.panel_document.setWindowTitle(QCoreApplication.translate("MainWindow", u"Document", None))
+ self.navigateUpButton.setText(QCoreApplication.translate("MainWindow", u"Up", None))
+#if QT_CONFIG(tooltip)
+ self.navigateUpButton.setToolTip(QCoreApplication.translate("MainWindow", u"Open the containing graph", None))
+#endif // QT_CONFIG(tooltip)
+ self.graphBreadcrumbLabel.setText(QCoreApplication.translate("MainWindow", u"Untitled", None))
+ self.workspaceModeLabel.setText(QCoreApplication.translate("MainWindow", u"Graph", None))
+ self.applyJsonButton.setText(QCoreApplication.translate("MainWindow", u"Apply JSON", None))
+ self.pointerToolButton.setText(QCoreApplication.translate("MainWindow", u"Pointer", None))
+ self.inputToolButton.setText(QCoreApplication.translate("MainWindow", u"Input", None))
+#if QT_CONFIG(tooltip)
+ self.inputToolButton.setToolTip(QCoreApplication.translate("MainWindow", u"Add an interface input", None))
+#endif // QT_CONFIG(tooltip)
+ self.outputToolButton.setText(QCoreApplication.translate("MainWindow", u"Output", None))
+#if QT_CONFIG(tooltip)
+ self.outputToolButton.setToolTip(QCoreApplication.translate("MainWindow", u"Add an interface output", None))
+#endif // QT_CONFIG(tooltip)
+ self.jsonEditor.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Component JSON", None))
+ self.emptyWorkspaceLabel.setText(QCoreApplication.translate("MainWindow", u"No document open", None))
+ self.menuFile.setTitle(QCoreApplication.translate("MainWindow", u"&File", None))
+ self.menuEdit.setTitle(QCoreApplication.translate("MainWindow", u"&Edit", None))
+ self.menuView.setTitle(QCoreApplication.translate("MainWindow", u"&View", None))
+ self.menuPanels.setTitle(QCoreApplication.translate("MainWindow", u"&Panels", None))
+ self.menuToolbars.setTitle(QCoreApplication.translate("MainWindow", u"&Toolbars", None))
+ self.menuHelp.setTitle(QCoreApplication.translate("MainWindow", u"&Help", None))
+ self.fileToolbar.setWindowTitle(QCoreApplication.translate("MainWindow", u"File", None))
+ self.editToolbar.setWindowTitle(QCoreApplication.translate("MainWindow", u"Edit", None))
+ self.transformToolbar.setWindowTitle(QCoreApplication.translate("MainWindow", u"Transform", None))
+ # retranslateUi
+