Added Status Bar with Flask API Server Link Exposing Variables captured in Borealis for use by other applications / systems
Added a menubar for workflow management (Save/Load/Close), as well as an About section for credits, updating, and finding the Gitea project on the Bunny Lab Gitea repository. Added automatic workflow centering when you load a workflow, so it spawns the loaded JSON nodes in the center instead of off-screen somewhere at the exact original coordinates. Changed the context menu and hyperlink colors to a more muted blue color
This commit is contained in:
parent
9d3ef80f57
commit
db848211fd
54
borealis.py
54
borealis.py
@ -97,7 +97,7 @@ def save_workflow(graph: NodeGraph):
|
|||||||
def load_workflow(graph: NodeGraph):
|
def load_workflow(graph: NodeGraph):
|
||||||
"""
|
"""
|
||||||
Loads a workflow (including node values, connections, positions, etc.)
|
Loads a workflow (including node values, connections, positions, etc.)
|
||||||
from a specified JSON file, and then centers the view on all loaded nodes.
|
from a specified JSON file, then centers the view on all loaded nodes.
|
||||||
"""
|
"""
|
||||||
ensure_workflows_folder()
|
ensure_workflows_folder()
|
||||||
file_filter = "JSON Files (*.json);;All Files (*.*)"
|
file_filter = "JSON Files (*.json);;All Files (*.*)"
|
||||||
@ -108,16 +108,15 @@ def load_workflow(graph: NodeGraph):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
graph.load_session(file_path)
|
graph.load_session(file_path)
|
||||||
|
|
||||||
# After loading, center the viewer on all nodes.
|
# After loading, center the viewer on all nodes.
|
||||||
all_nodes = graph.all_nodes()
|
all_nodes = graph.all_nodes()
|
||||||
if all_nodes:
|
if all_nodes:
|
||||||
graph.viewer().zoom_to_nodes([node.view for node in all_nodes])
|
graph.viewer().zoom_to_nodes([node.view for node in all_nodes])
|
||||||
|
|
||||||
print(f"Workflow loaded from {file_path}")
|
print(f"Workflow loaded from {file_path}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QtWidgets.QMessageBox.critical(None, "Error Loading Workflow", str(e))
|
QtWidgets.QMessageBox.critical(None, "Error Loading Workflow", str(e))
|
||||||
|
|
||||||
|
|
||||||
def import_nodes_from_folder(package_name):
|
def import_nodes_from_folder(package_name):
|
||||||
"""
|
"""
|
||||||
Recursively import all modules from the given package.
|
Recursively import all modules from the given package.
|
||||||
@ -219,21 +218,30 @@ class BorealisWindow(QtWidgets.QMainWindow):
|
|||||||
|
|
||||||
# Create a status bar
|
# Create a status bar
|
||||||
self.setStatusBar(QtWidgets.QStatusBar(self))
|
self.setStatusBar(QtWidgets.QStatusBar(self))
|
||||||
# Default status message
|
# Remove the resize handle from the status bar:
|
||||||
self.update_status_bar("Flask Server: http://0.0.0.0:5000/data")
|
self.statusBar().setSizeGripEnabled(False)
|
||||||
|
|
||||||
|
# Add a permanent clickable link to the right side of the status bar:
|
||||||
|
self.link_label = QtWidgets.QLabel()
|
||||||
|
self.link_label.setTextFormat(QtCore.Qt.RichText)
|
||||||
|
self.link_label.setOpenExternalLinks(True)
|
||||||
|
# Add a couple spaces after the URL using
|
||||||
|
# Also color style to match your "blue-ish" highlight:
|
||||||
|
self.link_label.setText(
|
||||||
|
"<a href='http://127.0.0.1:5000/data' "
|
||||||
|
"style='color: rgb(60,120,180); text-decoration: none;'>"
|
||||||
|
"Flask API Server: http://127.0.0.1:5000/data </a>"
|
||||||
|
)
|
||||||
|
self.statusBar().addPermanentWidget(self.link_label)
|
||||||
|
|
||||||
# Resize
|
# Resize
|
||||||
self.resize(1200, 800)
|
self.resize(1200, 800)
|
||||||
|
|
||||||
def _build_graph_context_menu(self, custom_nodes_by_category):
|
def _build_graph_context_menu(self, custom_nodes_by_category):
|
||||||
"""
|
"""
|
||||||
Build context menu and re-apply the custom stylesheet for a
|
Build context menu and apply custom stylesheet for the 'blue-ish' highlight.
|
||||||
'blue-ish' highlight, removing the pink/purple highlight.
|
|
||||||
"""
|
"""
|
||||||
# Grab the node graph's context menu
|
|
||||||
graph_context_menu = self.graph.get_context_menu("graph")
|
graph_context_menu = self.graph.get_context_menu("graph")
|
||||||
|
|
||||||
# We can define a custom style for the QMenu objects:
|
|
||||||
menu_stylesheet = """
|
menu_stylesheet = """
|
||||||
QMenu {
|
QMenu {
|
||||||
background-color: rgb(30, 30, 30);
|
background-color: rgb(30, 30, 30);
|
||||||
@ -253,22 +261,15 @@ class BorealisWindow(QtWidgets.QMainWindow):
|
|||||||
margin: 4px 8px;
|
margin: 4px 8px;
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Apply the custom style
|
|
||||||
if graph_context_menu and graph_context_menu.qmenu:
|
if graph_context_menu and graph_context_menu.qmenu:
|
||||||
graph_context_menu.qmenu.setStyleSheet(menu_stylesheet)
|
graph_context_menu.qmenu.setStyleSheet(menu_stylesheet)
|
||||||
|
|
||||||
# Top-level "Add Nodes" folder in the context menu
|
|
||||||
add_nodes_menu = graph_context_menu.add_menu("Add Nodes")
|
add_nodes_menu = graph_context_menu.add_menu("Add Nodes")
|
||||||
|
|
||||||
# If you want the same style for "Add Nodes" submenus:
|
|
||||||
if add_nodes_menu and add_nodes_menu.qmenu:
|
if add_nodes_menu and add_nodes_menu.qmenu:
|
||||||
add_nodes_menu.qmenu.setStyleSheet(menu_stylesheet)
|
add_nodes_menu.qmenu.setStyleSheet(menu_stylesheet)
|
||||||
|
|
||||||
# For each category, build a submenu under "Add Nodes"
|
|
||||||
for category, node_classes in custom_nodes_by_category.items():
|
for category, node_classes in custom_nodes_by_category.items():
|
||||||
category_menu = add_nodes_menu.add_menu(category)
|
category_menu = add_nodes_menu.add_menu(category)
|
||||||
# Also reapply style for each new sub-menu:
|
|
||||||
if category_menu and category_menu.qmenu:
|
if category_menu and category_menu.qmenu:
|
||||||
category_menu.qmenu.setStyleSheet(menu_stylesheet)
|
category_menu.qmenu.setStyleSheet(menu_stylesheet)
|
||||||
|
|
||||||
@ -280,7 +281,6 @@ class BorealisWindow(QtWidgets.QMainWindow):
|
|||||||
make_node_command(self.graph, node_type)
|
make_node_command(self.graph, node_type)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Provide a way to remove selected nodes
|
|
||||||
graph_context_menu.add_command(
|
graph_context_menu.add_command(
|
||||||
"Remove Selected Node",
|
"Remove Selected Node",
|
||||||
lambda: [self.graph.remove_node(node)
|
lambda: [self.graph.remove_node(node)
|
||||||
@ -288,12 +288,10 @@ class BorealisWindow(QtWidgets.QMainWindow):
|
|||||||
if self.graph.selected_nodes() else None
|
if self.graph.selected_nodes() else None
|
||||||
)
|
)
|
||||||
|
|
||||||
# No 'Workflows' portion here because we moved it into the top menubar.
|
|
||||||
|
|
||||||
def _build_menubar(self):
|
def _build_menubar(self):
|
||||||
menubar = self.menuBar()
|
menubar = self.menuBar()
|
||||||
|
|
||||||
# 1) Workflows menu in menubar
|
# Workflows menu
|
||||||
workflows_menu = menubar.addMenu("Workflows")
|
workflows_menu = menubar.addMenu("Workflows")
|
||||||
|
|
||||||
load_action = QtWidgets.QAction("Load Workflow", self)
|
load_action = QtWidgets.QAction("Load Workflow", self)
|
||||||
@ -308,20 +306,17 @@ class BorealisWindow(QtWidgets.QMainWindow):
|
|||||||
close_action.triggered.connect(lambda: close_workflow(self.graph))
|
close_action.triggered.connect(lambda: close_workflow(self.graph))
|
||||||
workflows_menu.addAction(close_action)
|
workflows_menu.addAction(close_action)
|
||||||
|
|
||||||
# 2) About menu
|
# About menu
|
||||||
about_menu = menubar.addMenu("About")
|
about_menu = menubar.addMenu("About")
|
||||||
|
|
||||||
# "Gitea Project" option
|
|
||||||
gitea_action = QtWidgets.QAction("Gitea Project", self)
|
gitea_action = QtWidgets.QAction("Gitea Project", self)
|
||||||
gitea_action.triggered.connect(self._open_gitea_project)
|
gitea_action.triggered.connect(self._open_gitea_project)
|
||||||
about_menu.addAction(gitea_action)
|
about_menu.addAction(gitea_action)
|
||||||
|
|
||||||
# "Credits" option
|
|
||||||
credits_action = QtWidgets.QAction("Credits", self)
|
credits_action = QtWidgets.QAction("Credits", self)
|
||||||
credits_action.triggered.connect(self._show_credits_popup)
|
credits_action.triggered.connect(self._show_credits_popup)
|
||||||
about_menu.addAction(credits_action)
|
about_menu.addAction(credits_action)
|
||||||
|
|
||||||
# "Check for Updates" option
|
|
||||||
updates_action = QtWidgets.QAction("Check for Updates", self)
|
updates_action = QtWidgets.QAction("Check for Updates", self)
|
||||||
updates_action.triggered.connect(self._show_updates_popup)
|
updates_action.triggered.connect(self._show_updates_popup)
|
||||||
about_menu.addAction(updates_action)
|
about_menu.addAction(updates_action)
|
||||||
@ -344,15 +339,6 @@ class BorealisWindow(QtWidgets.QMainWindow):
|
|||||||
"Built-in update functionality has not been built yet, but it's on the roadmap. Stay tuned."
|
"Built-in update functionality has not been built yet, but it's on the roadmap. Stay tuned."
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_status_bar(self, data: str):
|
|
||||||
"""
|
|
||||||
Flattens multi-line data into a single line
|
|
||||||
(using ' | ' to replace newlines)
|
|
||||||
and shows it in the status bar.
|
|
||||||
"""
|
|
||||||
flattened = data.replace("\n", " | ")
|
|
||||||
self.statusBar().showMessage(flattened)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
app = QtWidgets.QApplication(sys.argv)
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user