Source code for csaxs_bec.bec_ipython_client.plugins.LamNI.gui_tools

import builtins

from bec_widgets.cli.client import BECDockArea

# from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_get, epics_put, fshopen, fshclose

if builtins.__dict__.get("bec") is not None:
    bec = builtins.__dict__.get("bec")
    dev = builtins.__dict__.get("dev")
    scans = builtins.__dict__.get("scans")

[docs] def umv(*args): return scans.umv(*args, relative=False)
[docs] class LamniGuiToolsError(Exception): pass
[docs] class LamniGuiTools: def __init__(self): self.text_box = None self.progressbar = None def set_client(self, client): self.client = client self.gui = self.client.gui def lamnigui_show_gui(self): if "lamni" in self.gui.windows: self.gui.lamni.show() else: self.gui.new("lamni") def lamnigui_stop_gui(self): self.gui.lamni.hide() def lamnigui_raise(self): self.gui.lamni.raise_window() def lamnigui_show_xeyealign(self): self.lamnigui_show_gui() if self._lamnigui_check_attribute_not_exists("xeyegui"): self.lamnigui_remove_all_docks() self.xeyegui = self.gui.lamni.new("xeyegui").new("XRayEye") # start live if not dev.cam_xeye.live_mode: dev.cam_xeye.live_mode = True def _lamnigui_check_attribute_not_exists(self, attribute_name): if hasattr(self.gui,"lamni"): if hasattr(self.gui.lamni,attribute_name): return False return True def lamnigui_remove_all_docks(self): self.gui.lamni.delete_all() self.progressbar = None self.text_box = None def lamnigui_idle(self): self.lamnigui_show_gui() if self._lamnigui_check_attribute_not_exists("idle_text_box"): self.lamnigui_remove_all_docks() idle_text_box = self.gui.lamni.new("idle_textbox").new("TextBox") text = ( "<pre>" + "██████╗ ███████╗ ██████╗ ██╗ █████╗ ███╗ ███╗███╗ ██╗██╗\n" + "██╔══██╗██╔════╝██╔════╝ ██║ ██╔══██╗████╗ ████║████╗ ██║██║\n" + "██████╔╝█████╗ ██║ ██║ ███████║██╔████╔██║██╔██╗ ██║██║\n" + "██╔══██╗██╔══╝ ██║ ██║ ██╔══██║██║╚██╔╝██║██║╚██╗██║██║\n" + "██████╔╝███████╗╚██████╗ ███████╗██║ ██║██║ ╚═╝ ██║██║ ╚████║██║\n" + "╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝\n" + "</pre>" ) idle_text_box.set_html_text(text) def lamnigui_docs(self, filename: str | None = None): import csaxs_bec from pathlib import Path print("The general lamni documentation is at \nhttps://sls-csaxs.readthedocs.io/en/latest/user/ptychography/lamni.html#user-ptychography-lamni") csaxs_bec_basepath = Path(csaxs_bec.__file__).parent docs_folder = ( csaxs_bec_basepath / "bec_ipython_client" / "plugins" / "lamni" / "docs" ) if not docs_folder.is_dir(): raise NotADirectoryError(f"Docs folder not found: {docs_folder}") pdfs = sorted(docs_folder.glob("*.pdf")) if not pdfs: raise FileNotFoundError(f"No PDF files found in {docs_folder}") # --- Resolve PDF ------------------------------------------------------ if filename is not None: pdf_file = docs_folder / filename if not pdf_file.exists(): raise FileNotFoundError(f"Requested file not found: {filename}") else: print("\nAvailable lamni documentation PDFs:\n") for i, pdf in enumerate(pdfs, start=1): print(f" {i:2d}) {pdf.name}") print() while True: try: choice = int(input(f"Select a file (1–{len(pdfs)}): ")) if 1 <= choice <= len(pdfs): pdf_file = pdfs[choice - 1] break print(f"Enter a number between 1 and {len(pdfs)}.") except ValueError: print("Invalid input. Please enter a number.") # --- GUI handling (active existence check) ---------------------------- self.lamnigui_show_gui() if self._lamnigui_check_attribute_not_exists("PdfViewerWidget"): self.lamnigui_remove_all_docks() self.pdf_viewer = self.gui.lamni.new(widget="PdfViewerWidget") # --- Load PDF --------------------------------------------------------- self.pdf_viewer.PdfViewerWidget.load_pdf(str(pdf_file.resolve())) print(f"\nLoaded: {pdf_file.name}\n") def _lamnicam_check_device_exists(self, device): try: device except: return False else: return True def lamnigui_show_progress(self): self.lamnigui_show_gui() if self._lamnigui_check_attribute_not_exists("progressbar"): self.lamnigui_remove_all_docks() # Add a new dock with a RingProgressBar widget self.progressbar = self.gui.lamni.new("progressbar").new("RingProgressBar") # Customize the size of the progress ring self.progressbar.set_line_widths(20) # Disable automatic updates and manually set the self.progressbar value self.progressbar.enable_auto_updates(False) # Set precision for the self.progressbar display self.progressbar.set_precision(1) # Display self.progressbar with one decimal places # Setting multiple rigns with different values self.progressbar.set_number_of_bars(3) self.progressbar.rings[0].set_update("manual") self.progressbar.rings[1].set_update("manual") self.progressbar.rings[2].set_update("scan") # Set the values of the rings to 50, 75, and 25 from outer to inner ring # self.progressbar.set_value([50, 75]) # Add a new dock with a TextBox widget self.text_box = self.gui.lamni.new(name="progress_text").new("TextBox") self._lamnigui_update_progress() def _lamnigui_update_progress(self): if self.progressbar is not None: progress = self.progress["projection"] / self.progress["total_projections"] * 100 subtomo_progress = ( self.progress["subtomo_projection"] / self.progress["subtomo_total_projections"] * 100 ) self.progressbar.set_value([progress, subtomo_progress, 0]) if self.text_box is not None: text = f"Progress report:\n Tomo type: ....................... {self.progress['tomo_type']}\n Projection: ...................... {self.progress['projection']:.0f}\n Total projections expected ....... {self.progress['total_projections']}\n Angle: ........................... {self.progress['angle']}\n Current subtomo: ................. {self.progress['subtomo']}\n Current projection within subtomo: {self.progress['subtomo_projection']}\n Total projections per subtomo: ... {self.progress['subtomo_total_projections']}" self.text_box.set_plain_text(text)
if __name__ == "__main__": from bec_lib.client import BECClient from bec_widgets.cli.client_utils import BECGuiClient client = BECClient() client.start() client.gui = BECGuiClient() lamni_gui = LamniGuiTools(client) lamni_gui.lamnigui_show_gui() lamni_gui.lamnigui_show_progress()