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:
Nicole Rappe 2025-02-25 17:39:01 -07:00
parent 9d3ef80f57
commit db848211fd

View File

@ -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&nbsp;&nbsp;</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)