diff --git a/bec_widgets/widgets/__init__.py b/bec_widgets/widgets/__init__.py index ecbd45b7..7bff4848 100644 --- a/bec_widgets/widgets/__init__.py +++ b/bec_widgets/widgets/__init__.py @@ -1,4 +1,4 @@ from .monitor import BECMonitor, ConfigDialog from .scan_control import ScanControl -from .toolbar import ModularToolbar +from .toolbar import ModularToolBar from .editor import BECEditor diff --git a/bec_widgets/widgets/editor/editor.py b/bec_widgets/widgets/editor/editor.py index b6b6da9e..8870cc97 100644 --- a/bec_widgets/widgets/editor/editor.py +++ b/bec_widgets/widgets/editor/editor.py @@ -1,25 +1,17 @@ import subprocess import qdarktheme +from qtpy.Qsci import QsciScintilla, QsciLexerPython from qtpy.QtCore import QFile, QTextStream, Signal, QThread -from qtpy.QtGui import QColor, QFont, QAction, QShortcut, QKeySequence +from qtpy.QtGui import QColor, QFont from qtpy.QtWidgets import ( QApplication, - QMainWindow, QFileDialog, - QPushButton, QTextEdit, QVBoxLayout, QWidget, ) -# from PyQt6.Qsci import QsciScintilla, QsciLexerPython -from qtpy.Qsci import QsciScintilla, QsciLexerPython - -# from bec_widgets.widgets.toolbar.toolbar import ModularToolbar - -# from bec_widgets.widgets import ModularToolbar - class ScriptRunnerThread(QThread): outputSignal = Signal(str) @@ -57,20 +49,15 @@ class BECEditor(QWidget): self.editor = QsciScintilla() self.terminal = QTextEdit() self.terminal.setReadOnly(True) - # self.runButton = QPushButton("Run Script") # Layout - layout = QVBoxLayout() - layout.addWidget(self.editor) - # layout.addWidget(self.runButton) - layout.addWidget(self.terminal) - self.setLayout(layout) + self.layout = QVBoxLayout() + self.layout.addWidget(self.editor) + self.layout.addWidget(self.terminal) + self.setLayout(self.layout) self.setupEditor() - # Connect the run button - # self.runButton.clicked.connect(self.runScript) - def setupEditor(self): # Set the lexer for Python self.lexer = QsciLexerPython() @@ -89,8 +76,6 @@ class BECEditor(QWidget): # Additional UI elements like menu for load/save can be added here self.setEditorStyle() - self.createActions() - self.createMenus() def setEditorStyle(self): # Dracula Theme Colors @@ -137,23 +122,6 @@ class BECEditor(QWidget): def updateTerminal(self, text): self.terminal.append(text) - def createMenus(self): - ... - # self.fileMenu = self.menuBar().addMenu("&File") - # self.fileMenu.addAction(self.openAct) - # self.fileMenu.addAction(self.saveAct) - - def createActions(self): - self.openAct = QAction("&Open...", self, triggered=self.openFile) - self.saveAct = QAction("&Save", self, triggered=self.saveFile) - - # Shortcuts - self.openShortcut = QShortcut(QKeySequence("Ctrl+O"), self) - self.openShortcut.activated.connect(self.openFile) - - self.saveShortcut = QShortcut(QKeySequence("Ctrl+S"), self) - self.saveShortcut.activated.connect(self.saveFile) - def openFile(self): path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Python files (*.py)") if path: @@ -174,28 +142,16 @@ class BECEditor(QWidget): if __name__ == "__main__": - from bec_widgets.widgets.toolbar.toolbar import ModularToolbar + from bec_widgets.widgets.toolbar.toolbar import ModularToolBar - # app = QApplication([]) - # qdarktheme.setup_theme("auto") - # mainWin = BECEditor() - # mainWin.show() - # app.exec() app = QApplication([]) qdarktheme.setup_theme("auto") - window = QWidget() - layout = QVBoxLayout(window) - editor = BECEditor() - # toolbar_auto = ModularToolbar() + mainWin = BECEditor() - # Manual initialization - toolbar_manual = ModularToolbar(auto_init=False) - toolbar_manual.set_target_widget(editor) + toolbar_manual = ModularToolBar() + toolbar_manual.set_target_widget(mainWin) - layout.addWidget(toolbar_manual) - layout.addWidget(editor) - - window.setLayout(layout) - window.show() + mainWin.layout.insertWidget(0, toolbar_manual) + mainWin.show() app.exec() diff --git a/bec_widgets/widgets/toolbar/__init__.py b/bec_widgets/widgets/toolbar/__init__.py index de994213..ef8fe1cd 100644 --- a/bec_widgets/widgets/toolbar/__init__.py +++ b/bec_widgets/widgets/toolbar/__init__.py @@ -1 +1 @@ -from .toolbar import ModularToolbar +from .toolbar import ModularToolBar diff --git a/bec_widgets/widgets/toolbar/toolbar.py b/bec_widgets/widgets/toolbar/toolbar.py index 0bdf194f..eb90c7d9 100644 --- a/bec_widgets/widgets/toolbar/toolbar.py +++ b/bec_widgets/widgets/toolbar/toolbar.py @@ -1,127 +1,73 @@ -from PyQt6.QtCore import QTimer -from PyQt6.QtWidgets import QPushButton +from PyQt6.QtWidgets import QToolBar +from qtpy.QtCore import QTimer +from qtpy.QtGui import QAction +from qtpy.QtWidgets import QPushButton from abc import ABC, abstractmethod -from PyQt6.QtWidgets import QHBoxLayout, QWidget +from qtpy.QtWidgets import QHBoxLayout, QWidget from bec_widgets.widgets.editor.editor import BECEditor -class AbstractToolbarButton(QPushButton): # , ABC): #TODO decide if ABC useful for this case.. - def __init__(self, text, slot_name, parent=None): - super().__init__(text, parent) - self.slot_name = slot_name - - # @abstractmethod - def setup_button(self): - """ - Setup specific properties for the button. - """ +class ToolBarAction(ABC): + @abstractmethod + def create(self, target: QWidget): pass - def connect_to_widget(self, widget): - slot_function = getattr(widget, self.slot_name, None) - if slot_function and callable(slot_function): - self.clicked.connect(slot_function) + +class OpenFileAction: # (ToolBarAction): + def create(self, target: QWidget): + action = QAction("Open File", target) + action.triggered.connect(target.openFile) + return action -class OpenFileButton(AbstractToolbarButton): +class SaveFileAction: + def create(self, target): + action = QAction("Save File", target) + action.triggered.connect(target.saveFile) + return action + + +class RunScriptAction: + def create(self, target): + action = QAction("Run Script", target) + action.triggered.connect(target.runScript) + return action + + +class ModularToolBar(QToolBar): def __init__(self, parent=None): - super().__init__("Open File", "openFile", parent) - self.setup_button() - - def setup_button(self): - self.setText("Open File") - # Add specific setup for Open File Button - # pass - - -class SaveFileButton(AbstractToolbarButton): - def __init__(self, parent=None): - super().__init__("Save File", "saveFile", parent) - self.setup_button() - - def setup_button(self): - self.setText("Save File") - # Add specific setup for Save File Button - # pass - - -class RunScriptButton(AbstractToolbarButton): - def __init__(self, parent=None): - super().__init__("Run Script", "runScript", parent) - self.setup_button() - - def setup_button(self): - # Add specific setup for Run Script Button - self.setText("Run Script") - # pass - - -class ModularToolbar(QWidget): - def __init__(self, parent=None, auto_init=False): super().__init__(parent) - # self.layout = QHBoxLayout() - # self.setLayout(self.layout) - # self.initialized = False - self.layout = QHBoxLayout() - self.setLayout(self.layout) - self.current_widget = None - self.auto_init = auto_init - self.initialized = False - if self.auto_init: - QTimer.singleShot(0, self.detect_context_and_update_buttons) - - def set_target_widget(self, widget): - self.current_widget = widget - self.update_buttons() - - def showEvent(self, event): - super().showEvent(event) - if not self.initialized: - self.detect_context_and_update_buttons() - self.initialized = True - - def detect_context_and_update_buttons(self): - if not self.auto_init or self.initialized: - return + self.handler = { + BECEditor: [OpenFileAction(), SaveFileAction(), RunScriptAction()], + # BECMonitor: [SomeOtherAction(), AnotherAction()], # Example for another widget + } # TODO also buggy fox later + QTimer.singleShot(0, self.detect_context_and_update_actions) # TODO buggy disabled for now + self.setStyleSheet("QToolBar { background: transparent; }") + def detect_context_and_update_actions(self): # TODO buggy disabled for now parent_widget = self.parent() if parent_widget is None: return for child in parent_widget.children(): - if isinstance(child, BECEditor): - self.set_widget(child) - print("BECEditor init success!") - break - else: - print("no supported widget detected") + for widget_type, actions in self.handler.items(): + if isinstance(child, widget_type): + self.populate_toolbar(child, actions) + return - def set_widget(self, widget): - self.clear_buttons() - self.add_buttons([OpenFileButton(), SaveFileButton(), RunScriptButton()]) - self.connectToWidget(widget) + def set_target_widget(self, widget): + self.populate_toolbar( + widget, actions=[OpenFileAction(), SaveFileAction(), RunScriptAction()] + ) + # for widget_type, actions in self.handler.items(): #TODO for automatic population + # if isinstance(widget, widget_type): + # self.populate_toolbar(widget, actions) + # break - def update_buttons(self): - if self.current_widget is None: - return - - self.clear_buttons() - # if isinstance(self.current_widget, BECEditor): - self.add_buttons([OpenFileButton(), SaveFileButton(), RunScriptButton()]) - # Additional conditions for other widget types can be added here - - def clear_buttons(self): - for button in self.findChildren(AbstractToolbarButton): - self.layout.removeWidget(button) - button.deleteLater() - - def add_buttons(self, buttons): - for button in buttons: - self.layout.addWidget(button) - button.connect_to_widget(self.current_widget) - - def connectToWidget(self, target_widget): - for button in self.findChildren(AbstractToolbarButton): - button.connect_to_widget(target_widget) + def populate_toolbar(self, target_widget, actions): + self.clear() + for action_creator in actions: + action = action_creator.create(target_widget) + self.addAction(action)