mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 11:41:49 +02:00
refactor: toolbar.py migration to native qt QToolBar
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
from .monitor import BECMonitor, ConfigDialog
|
from .monitor import BECMonitor, ConfigDialog
|
||||||
from .scan_control import ScanControl
|
from .scan_control import ScanControl
|
||||||
from .toolbar import ModularToolbar
|
from .toolbar import ModularToolBar
|
||||||
from .editor import BECEditor
|
from .editor import BECEditor
|
||||||
|
@ -1,25 +1,17 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import qdarktheme
|
import qdarktheme
|
||||||
|
from qtpy.Qsci import QsciScintilla, QsciLexerPython
|
||||||
from qtpy.QtCore import QFile, QTextStream, Signal, QThread
|
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 (
|
from qtpy.QtWidgets import (
|
||||||
QApplication,
|
QApplication,
|
||||||
QMainWindow,
|
|
||||||
QFileDialog,
|
QFileDialog,
|
||||||
QPushButton,
|
|
||||||
QTextEdit,
|
QTextEdit,
|
||||||
QVBoxLayout,
|
QVBoxLayout,
|
||||||
QWidget,
|
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):
|
class ScriptRunnerThread(QThread):
|
||||||
outputSignal = Signal(str)
|
outputSignal = Signal(str)
|
||||||
@ -57,20 +49,15 @@ class BECEditor(QWidget):
|
|||||||
self.editor = QsciScintilla()
|
self.editor = QsciScintilla()
|
||||||
self.terminal = QTextEdit()
|
self.terminal = QTextEdit()
|
||||||
self.terminal.setReadOnly(True)
|
self.terminal.setReadOnly(True)
|
||||||
# self.runButton = QPushButton("Run Script")
|
|
||||||
|
|
||||||
# Layout
|
# Layout
|
||||||
layout = QVBoxLayout()
|
self.layout = QVBoxLayout()
|
||||||
layout.addWidget(self.editor)
|
self.layout.addWidget(self.editor)
|
||||||
# layout.addWidget(self.runButton)
|
self.layout.addWidget(self.terminal)
|
||||||
layout.addWidget(self.terminal)
|
self.setLayout(self.layout)
|
||||||
self.setLayout(layout)
|
|
||||||
|
|
||||||
self.setupEditor()
|
self.setupEditor()
|
||||||
|
|
||||||
# Connect the run button
|
|
||||||
# self.runButton.clicked.connect(self.runScript)
|
|
||||||
|
|
||||||
def setupEditor(self):
|
def setupEditor(self):
|
||||||
# Set the lexer for Python
|
# Set the lexer for Python
|
||||||
self.lexer = QsciLexerPython()
|
self.lexer = QsciLexerPython()
|
||||||
@ -89,8 +76,6 @@ class BECEditor(QWidget):
|
|||||||
|
|
||||||
# Additional UI elements like menu for load/save can be added here
|
# Additional UI elements like menu for load/save can be added here
|
||||||
self.setEditorStyle()
|
self.setEditorStyle()
|
||||||
self.createActions()
|
|
||||||
self.createMenus()
|
|
||||||
|
|
||||||
def setEditorStyle(self):
|
def setEditorStyle(self):
|
||||||
# Dracula Theme Colors
|
# Dracula Theme Colors
|
||||||
@ -137,23 +122,6 @@ class BECEditor(QWidget):
|
|||||||
def updateTerminal(self, text):
|
def updateTerminal(self, text):
|
||||||
self.terminal.append(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):
|
def openFile(self):
|
||||||
path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Python files (*.py)")
|
path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Python files (*.py)")
|
||||||
if path:
|
if path:
|
||||||
@ -174,28 +142,16 @@ class BECEditor(QWidget):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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([])
|
app = QApplication([])
|
||||||
qdarktheme.setup_theme("auto")
|
qdarktheme.setup_theme("auto")
|
||||||
window = QWidget()
|
|
||||||
layout = QVBoxLayout(window)
|
|
||||||
|
|
||||||
editor = BECEditor()
|
mainWin = BECEditor()
|
||||||
# toolbar_auto = ModularToolbar()
|
|
||||||
|
|
||||||
# Manual initialization
|
toolbar_manual = ModularToolBar()
|
||||||
toolbar_manual = ModularToolbar(auto_init=False)
|
toolbar_manual.set_target_widget(mainWin)
|
||||||
toolbar_manual.set_target_widget(editor)
|
|
||||||
|
|
||||||
layout.addWidget(toolbar_manual)
|
mainWin.layout.insertWidget(0, toolbar_manual)
|
||||||
layout.addWidget(editor)
|
mainWin.show()
|
||||||
|
|
||||||
window.setLayout(layout)
|
|
||||||
window.show()
|
|
||||||
app.exec()
|
app.exec()
|
||||||
|
@ -1 +1 @@
|
|||||||
from .toolbar import ModularToolbar
|
from .toolbar import ModularToolBar
|
||||||
|
@ -1,127 +1,73 @@
|
|||||||
from PyQt6.QtCore import QTimer
|
from PyQt6.QtWidgets import QToolBar
|
||||||
from PyQt6.QtWidgets import QPushButton
|
from qtpy.QtCore import QTimer
|
||||||
|
from qtpy.QtGui import QAction
|
||||||
|
from qtpy.QtWidgets import QPushButton
|
||||||
from abc import ABC, abstractmethod
|
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
|
from bec_widgets.widgets.editor.editor import BECEditor
|
||||||
|
|
||||||
|
|
||||||
class AbstractToolbarButton(QPushButton): # , ABC): #TODO decide if ABC useful for this case..
|
class ToolBarAction(ABC):
|
||||||
def __init__(self, text, slot_name, parent=None):
|
@abstractmethod
|
||||||
super().__init__(text, parent)
|
def create(self, target: QWidget):
|
||||||
self.slot_name = slot_name
|
|
||||||
|
|
||||||
# @abstractmethod
|
|
||||||
def setup_button(self):
|
|
||||||
"""
|
|
||||||
Setup specific properties for the button.
|
|
||||||
"""
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def connect_to_widget(self, widget):
|
|
||||||
slot_function = getattr(widget, self.slot_name, None)
|
class OpenFileAction: # (ToolBarAction):
|
||||||
if slot_function and callable(slot_function):
|
def create(self, target: QWidget):
|
||||||
self.clicked.connect(slot_function)
|
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):
|
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)
|
super().__init__(parent)
|
||||||
# self.layout = QHBoxLayout()
|
self.handler = {
|
||||||
# self.setLayout(self.layout)
|
BECEditor: [OpenFileAction(), SaveFileAction(), RunScriptAction()],
|
||||||
# self.initialized = False
|
# BECMonitor: [SomeOtherAction(), AnotherAction()], # Example for another widget
|
||||||
self.layout = QHBoxLayout()
|
} # TODO also buggy fox later
|
||||||
self.setLayout(self.layout)
|
QTimer.singleShot(0, self.detect_context_and_update_actions) # TODO buggy disabled for now
|
||||||
self.current_widget = None
|
self.setStyleSheet("QToolBar { background: transparent; }")
|
||||||
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
|
|
||||||
|
|
||||||
|
def detect_context_and_update_actions(self): # TODO buggy disabled for now
|
||||||
parent_widget = self.parent()
|
parent_widget = self.parent()
|
||||||
if parent_widget is None:
|
if parent_widget is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
for child in parent_widget.children():
|
for child in parent_widget.children():
|
||||||
if isinstance(child, BECEditor):
|
for widget_type, actions in self.handler.items():
|
||||||
self.set_widget(child)
|
if isinstance(child, widget_type):
|
||||||
print("BECEditor init success!")
|
self.populate_toolbar(child, actions)
|
||||||
break
|
return
|
||||||
else:
|
|
||||||
print("no supported widget detected")
|
|
||||||
|
|
||||||
def set_widget(self, widget):
|
def set_target_widget(self, widget):
|
||||||
self.clear_buttons()
|
self.populate_toolbar(
|
||||||
self.add_buttons([OpenFileButton(), SaveFileButton(), RunScriptButton()])
|
widget, actions=[OpenFileAction(), SaveFileAction(), RunScriptAction()]
|
||||||
self.connectToWidget(widget)
|
)
|
||||||
|
# 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):
|
def populate_toolbar(self, target_widget, actions):
|
||||||
if self.current_widget is None:
|
self.clear()
|
||||||
return
|
for action_creator in actions:
|
||||||
|
action = action_creator.create(target_widget)
|
||||||
self.clear_buttons()
|
self.addAction(action)
|
||||||
# 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)
|
|
||||||
|
Reference in New Issue
Block a user