Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
34b2800
feat(bec_widget): save screenshot to bytes
wyzula-jan Oct 20, 2025
4bc36eb
fix(widget_state_manager): added shiboken check
wyzula-jan Nov 9, 2025
17b0d60
fix(dark_mode_button): skip settings added
wyzula-jan Nov 9, 2025
33942a6
fix(main_window): cleanup adjusted with shiboken6
wyzula-jan Oct 26, 2025
8b8edd4
feat(advanced_dock_area): UI/UX for profile management improved, savi…
wyzula-jan Oct 6, 2025
e6ca82f
fix(advanced_dock_area): disable developer mode switch
wyzula-jan Oct 27, 2025
e8eb1c0
fix(main_window): removed general forced cleanup
wyzula-jan Nov 7, 2025
b74f5b6
feat(advanced_dock_area): created DockAreaWidget base class; profile …
wyzula-jan Nov 4, 2025
cfdb859
refactor(monaco_dock): changed to use DockAreaWidget
wyzula-jan Nov 5, 2025
991cb01
refactor(developer_view): changed to use DockAreaWidget
wyzula-jan Nov 5, 2025
b170ab0
refactor(main_app): adapted for DockAreaWidget changes
wyzula-jan Nov 9, 2025
9802540
fix(widget_state_manager): visible is always true
wyzula-jan Nov 19, 2025
8a741e0
fix(ide_explorer): light mode fixed
wyzula-jan Nov 19, 2025
0176204
fix(qt_ads): pythons stubs match structure of PySide6QtAds
wyzula-jan Nov 19, 2025
9905b49
fix(widget_io): find ancestor returns correct type
wyzula-jan Nov 19, 2025
7fc2976
fix(bec_widget): improved qt enums; grab safeguard
wyzula-jan Nov 19, 2025
5a64bf2
fix(client): client regenerated
wyzula-jan Nov 10, 2025
07d84d9
fix(widget_state_manager): always setting visible to true
wyzula-jan Nov 20, 2025
feeb20f
feat(widget_state_manager): can serialize from root
wyzula-jan Nov 20, 2025
06eb417
fix(widget_state_manager): skip property listed introduced
wyzula-jan Nov 20, 2025
6be0da6
fix(widget_state_manager): IDEExplorer plugin not initialised in desi…
wyzula-jan Nov 20, 2025
a75651e
fix(widgets): removed isVisible from all SafeProperties
wyzula-jan Nov 20, 2025
d181537
feat(advanced_dock_area): instance lock for multiple ads in same session
wyzula-jan Nov 20, 2025
53ece6c
fix(widget_state_manager): visibility managed by parent
wyzula-jan Nov 20, 2025
3dc376e
WIP removed for device manager
wyzula-jan Nov 20, 2025
b9056f6
refactor(device-manager-view): update view to bec_widgets.QtAds
cappel89 Oct 20, 2025
382287b
feat(device-config-template): add device config template widget
cappel89 Oct 20, 2025
1cde79c
refactor(device-manager-view): add config form dialog to DM view
cappel89 Oct 20, 2025
8d1eb22
refactor(dm-ophyd-test): Refactor dm-ophyd-test; Add Config and Conne…
cappel89 Oct 23, 2025
53c5a8b
fix(dm-ophyd-test): refactor device-table-view and dm-view
cappel89 Oct 23, 2025
48a55b5
wip show legend until legend solution is discussed
cappel89 Oct 23, 2025
fc1048a
wip minor improvements
cappel89 Oct 27, 2025
618cc78
wip tests
cappel89 Oct 27, 2025
5fe3738
refactor(device-manager-view): Add enable/disable of upload to redis …
cappel89 Oct 27, 2025
2b686aa
wip add cleanup logic for OphydDeviceTest implemented as a Dialog
cappel89 Oct 27, 2025
3ef7e1d
wip improve performance for redis compar...
cappel89 Oct 27, 2025
8025bcc
wip add enable action to update redis
cappel89 Oct 27, 2025
438f35a
drop camelCase in header names
cappel89 Oct 27, 2025
744c098
refactor(device-manager-view): add upload_redis_dialog, cleanup, fix …
cappel89 Oct 28, 2025
9a6f79e
wip
cappel89 Oct 28, 2025
ff678d9
refactor(device-manager-view): cleanup and bugfixes
cappel89 Oct 31, 2025
c5149ac
refactor(dm-config-view): cleanup and tests
cappel89 Nov 2, 2025
eecbd46
wip refactor to DeviceTable
cappel89 Nov 3, 2025
7c1a318
wip fix table sorting
cappel89 Nov 3, 2025
e1614bc
feat(bec-list): Add wrapper around QListWidget with simplified API
cappel89 Nov 11, 2025
4fe66db
refactor(ophyd-test): refactor ophyd test widget
cappel89 Nov 11, 2025
bc333d4
wip delete ophyd_test
cappel89 Nov 11, 2025
3398780
wip save state
cappel89 Nov 11, 2025
c8744f4
wip tests
cappel89 Nov 11, 2025
496647f
wip improvements of the code, remove ghost item
cappel89 Nov 11, 2025
740707c
wip
cappel89 Nov 11, 2025
b4dabfa
wip fix tests
cappel89 Nov 13, 2025
6eca765
wip
cappel89 Nov 13, 2025
1f1eddc
fix(conftest): make SafeSlot raise per default in unit tests
cappel89 Nov 13, 2025
8d0ff76
wip fix tests
cappel89 Nov 13, 2025
44cb230
refactor(table): move away from custom widgets in table, checkable, t…
cappel89 Nov 14, 2025
c66b211
wip
cappel89 Nov 14, 2025
67a8a52
wip test coverage
cappel89 Nov 14, 2025
3c4f0e8
wip
cappel89 Nov 14, 2025
9aa014c
wip set RPC=False for all widgets of dm view
cappel89 Nov 14, 2025
3eb879e
test(bec-list): add tests for beclist widget
cappel89 Nov 14, 2025
9754df0
wip cleanup
cappel89 Nov 14, 2025
00d4c40
WIP client regenerated
wyzula-jan Nov 18, 2025
e4fa406
wip import optimised
wyzula-jan Nov 18, 2025
b15d883
wip fix yaml_load wrong import
wyzula-jan Nov 18, 2025
f43709b
wip device_manager_view migrated to new DockAreaWidget
wyzula-jan Nov 20, 2025
f9645f5
wip splitter logic removed from view
wyzula-jan Nov 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions bec_widgets/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import os
import sys

import PySide6QtAds as QtAds

import bec_widgets.widgets.containers.qt_ads as QtAds
from bec_widgets.utils.bec_widget import BECWidget
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot

Expand Down
5 changes: 4 additions & 1 deletion bec_widgets/applications/main_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ def __init__(

def _add_views(self):
self.add_section("BEC Applications", "bec_apps")
self.ads = AdvancedDockArea(self)
self.ads = AdvancedDockArea(
self, profile_namespace="main_workspace", auto_profile_namespace=False
)
self.ads.setObjectName("MainWorkspace")
self.device_manager = DeviceManagerWidget(self)
self.developer_view = DeveloperView(self)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ def __init__(
self.developer_widget = DeveloperWidget(parent=self)
self.set_content(self.developer_widget)

# Apply stretch after the layout is done
self.set_default_view([2, 5, 3], [7, 3])


if __name__ == "__main__":
import sys
Expand Down
157 changes: 89 additions & 68 deletions bec_widgets/applications/views/developer_view/developer_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@
from bec_lib.script_executor import upload_script
from bec_qthemes import material_icon
from qtpy.QtGui import QKeySequence, QShortcut
from qtpy.QtWidgets import QTextEdit, QVBoxLayout, QWidget
from shiboken6 import isValid
from qtpy.QtWidgets import QTextEdit

import bec_widgets.widgets.containers.ads as QtAds
from bec_widgets import BECWidget
from bec_widgets.utils.error_popups import SafeSlot
from bec_widgets.utils.toolbars.actions import MaterialIconAction
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
from bec_widgets.utils.toolbars.toolbar import ModularToolBar
from bec_widgets.widgets.containers.ads import CDockManager, CDockWidget
from bec_widgets.widgets.containers.advanced_dock_area.advanced_dock_area import AdvancedDockArea
from bec_widgets.widgets.containers.advanced_dock_area.basic_dock_area import DockAreaWidget
from bec_widgets.widgets.editors.monaco.monaco_dock import MonacoDock
from bec_widgets.widgets.editors.web_console.web_console import WebConsole
from bec_widgets.widgets.utility.ide_explorer.ide_explorer import IDEExplorer
Expand Down Expand Up @@ -77,31 +74,38 @@ def replace_python_examples(match):
return css + html


class DeveloperWidget(BECWidget, QWidget):
class DeveloperWidget(DockAreaWidget):

def __init__(self, parent=None, **kwargs):
super().__init__(parent=parent, **kwargs)
super().__init__(parent=parent, variant="compact", **kwargs)

# Top-level layout hosting a toolbar and the dock manager
self._root_layout = QVBoxLayout(self)
self._root_layout.setContentsMargins(0, 0, 0, 0)
self._root_layout.setSpacing(0)
# Promote toolbar above the dock manager provided by the base class
self.toolbar = ModularToolBar(self)
self.init_developer_toolbar()
self._root_layout.addWidget(self.toolbar)

self.dock_manager = CDockManager(self)
self.dock_manager.setStyleSheet("")
self._root_layout.addWidget(self.dock_manager)
self._root_layout.insertWidget(0, self.toolbar)

# Initialize the widgets
self.explorer = IDEExplorer(self)
self.explorer.setObjectName("Explorer")
self.console = WebConsole(self)
self.console.setObjectName("Console")
self.terminal = WebConsole(self, startup_cmd="")
self.terminal.setObjectName("Terminal")
self.monaco = MonacoDock(self)
self.monaco.setObjectName("MonacoEditor")
self.monaco.save_enabled.connect(self._on_save_enabled_update)
self.plotting_ads = AdvancedDockArea(self, mode="plot", default_add_direction="bottom")
self.plotting_ads = AdvancedDockArea(
self,
mode="plot",
default_add_direction="bottom",
profile_namespace="developer_plotting",
auto_profile_namespace=False,
enable_profile_management=False,
variant="compact",
)
self.plotting_ads.setObjectName("PlottingArea")
self.signature_help = QTextEdit(self)
self.signature_help.setObjectName("Signature Help")
self.signature_help.setAcceptRichText(True)
self.signature_help.setReadOnly(True)
self.signature_help.setLineWrapMode(QTextEdit.LineWrapMode.WidgetWidth)
Expand All @@ -113,56 +117,83 @@ def __init__(self, parent=None, **kwargs):
)
self._current_script_id: str | None = None

# Create the dock widgets
self.explorer_dock = QtAds.CDockWidget("Explorer", self)
self.explorer_dock.setWidget(self.explorer)

self.console_dock = QtAds.CDockWidget("Console", self)
self.console_dock.setWidget(self.console)
self._initialize_layout()

self.monaco_dock = QtAds.CDockWidget("Monaco Editor", self)
self.monaco_dock.setWidget(self.monaco)

self.terminal_dock = QtAds.CDockWidget("Terminal", self)
self.terminal_dock.setWidget(self.terminal)
# Connect editor signals
self.explorer.file_open_requested.connect(self._open_new_file)
self.monaco.macro_file_updated.connect(self.explorer.refresh_macro_file)

# Monaco will be central widget
self.dock_manager.setCentralWidget(self.monaco_dock)
self.toolbar.show_bundles(["save", "execution", "settings"])

# Add the dock widgets to the dock manager
area_bottom = self.dock_manager.addDockWidget(
QtAds.DockWidgetArea.BottomDockWidgetArea, self.console_dock
def _initialize_layout(self) -> None:
"""Create the default dock arrangement for the developer workspace."""

# Monaco editor as the central dock
self.monaco_dock = self.new(
self.monaco,
closable=False,
floatable=False,
movable=False,
return_dock=True,
show_title_bar=False,
show_settings_action=False,
title_buttons={"float": False, "close": False, "menu": False},
# promote_central=True,
)
self.dock_manager.addDockWidgetTabToArea(self.terminal_dock, area_bottom)

area_left = self.dock_manager.addDockWidget(
QtAds.DockWidgetArea.LeftDockWidgetArea, self.explorer_dock
# Explorer on the left without a title bar
self.explorer_dock = self.new(
self.explorer,
where="left",
closable=False,
floatable=False,
movable=False,
return_dock=True,
show_title_bar=False,
)
area_left.titleBar().setVisible(False)

for dock in self.dock_manager.dockWidgets():
# dock.setFeature(CDockWidget.DockWidgetDeleteOnClose, True)#TODO implement according to MonacoDock or AdvancedDockArea
# dock.setFeature(CDockWidget.CustomCloseHandling, True) #TODO same
dock.setFeature(CDockWidget.DockWidgetFeature.DockWidgetClosable, False)
dock.setFeature(CDockWidget.DockWidgetFeature.DockWidgetFloatable, False)
dock.setFeature(CDockWidget.DockWidgetFeature.DockWidgetMovable, False)

self.plotting_ads_dock = QtAds.CDockWidget("Plotting Area", self)
self.plotting_ads_dock.setWidget(self.plotting_ads)

self.signature_dock = QtAds.CDockWidget("Signature Help", self)
self.signature_dock.setWidget(self.signature_help)

area_right = self.dock_manager.addDockWidget(
QtAds.DockWidgetArea.RightDockWidgetArea, self.plotting_ads_dock
# Console and terminal tabbed along the bottom
self.console_dock = self.new(
self.console,
relative_to=self.monaco_dock,
where="bottom",
closable=False,
floatable=False,
movable=False,
return_dock=True,
title_buttons={"float": True, "close": False},
)
self.terminal_dock = self.new(
self.terminal,
closable=False,
floatable=False,
movable=False,
tab_with=self.console_dock,
return_dock=True,
title_buttons={"float": False, "close": False},
)
self.dock_manager.addDockWidgetTabToArea(self.signature_dock, area_right)

# Connect editor signals
self.explorer.file_open_requested.connect(self._open_new_file)
self.monaco.macro_file_updated.connect(self.explorer.refresh_macro_file)
# Plotting area on the right with signature help tabbed alongside
self.plotting_ads_dock = self.new(
self.plotting_ads,
where="right",
closable=False,
floatable=False,
movable=False,
return_dock=True,
title_buttons={"float": True},
)
self.signature_dock = self.new(
self.signature_help,
closable=False,
floatable=False,
movable=False,
tab_with=self.plotting_ads_dock,
return_dock=True,
title_buttons={"float": False, "close": False},
)

self.toolbar.show_bundles(["save", "execution", "settings"])
self.set_layout_ratios(horizontal=[2, 5, 3], vertical=[7, 3])

def init_developer_toolbar(self):
"""Initialize the developer toolbar with necessary actions and widgets."""
Expand Down Expand Up @@ -313,19 +344,9 @@ def on_script_execution_info(self, content: dict, metadata: dict):
self.script_editor_tab.widget().set_highlighted_lines(line_number, line_number)

def cleanup(self):
for dock in self.dock_manager.dockWidgets():
self._delete_dock(dock)
self.delete_all()
return super().cleanup()

def _delete_dock(self, dock: CDockWidget) -> None:
w = dock.widget()
if w and isValid(w):
w.close()
w.deleteLater()
if isValid(dock):
dock.closeDockWidget()
dock.deleteDockWidget()


if __name__ == "__main__":
import sys
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .config_choice_dialog import ConfigChoiceDialog
from .device_form_dialog import DeviceFormDialog
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Dialog to chgoose config loading method: replace, add or cancel."""

from enum import IntEnum

from qtpy.QtWidgets import QDialog, QDialogButtonBox, QLabel, QSizePolicy, QVBoxLayout


class ConfigChoiceDialog(QDialog):
class Result(IntEnum):
CANCEL = QDialog.Rejected
ADD = 2
REPLACE = 3

def __init__(
self,
parent=None,
custom_label: str = "Do you want to replace the current config or add to it?",
):
super().__init__(parent)
self.setWindowTitle("Load Config")

layout = QVBoxLayout(self)

label = QLabel(custom_label)
label.setWordWrap(True)
layout.addWidget(label)

# Use QDialogButtonBox for native layout
self.button_box = QDialogButtonBox(self)
self.cancel_btn = self.button_box.addButton(
"Cancel", QDialogButtonBox.ButtonRole.ActionRole # RejectRole will be next to Accept...
)
self.replace_btn = self.button_box.addButton(
"Replace", QDialogButtonBox.ButtonRole.AcceptRole
)
self.add_btn = self.button_box.addButton("Add", QDialogButtonBox.ButtonRole.AcceptRole)

layout.addWidget(self.button_box)

for btn in [self.replace_btn, self.add_btn, self.cancel_btn]:
btn.setMinimumWidth(80)
btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)

# Connections using native done(int)
self.replace_btn.clicked.connect(lambda: self.done(self.Result.REPLACE))
self.add_btn.clicked.connect(lambda: self.done(self.Result.ADD))
self.cancel_btn.clicked.connect(lambda: self.done(self.Result.CANCEL))

self.replace_btn.setFocus()
Loading
Loading