From 80e1384bde2a40973ee191e1c3a6023eaba7f0c8 Mon Sep 17 00:00:00 2001 From: Adam Tyson Date: Thu, 21 Dec 2023 13:29:34 +0000 Subject: [PATCH] Remove GUI --- MANIFEST.in | 1 - brainrender/gui/__init__.py | 37 --- brainrender/gui/app.py | 228 -------------- brainrender/gui/apputils/__init__.py | 0 brainrender/gui/apputils/actors_control.py | 114 ------- .../gui/apputils/add_from_file_control.py | 92 ------ brainrender/gui/apputils/camera_control.py | 47 --- brainrender/gui/apputils/regions_control.py | 106 ------- brainrender/gui/icons/BG_logo_mini.svg | 102 ------- brainrender/gui/icons/__init__.py | 0 brainrender/gui/icons/box_dark.svg | 14 - brainrender/gui/icons/box_light.svg | 12 - brainrender/gui/icons/checkedbox_dark.svg | 14 - brainrender/gui/icons/checkedbox_light.svg | 14 - brainrender/gui/icons/down_dark.svg | 14 - brainrender/gui/icons/down_light.svg | 14 - brainrender/gui/icons/eye-slash.svg | 5 - brainrender/gui/icons/eye.svg | 5 - brainrender/gui/icons/right_dark.svg | 14 - brainrender/gui/icons/right_light.svg | 14 - brainrender/gui/style.py | 198 ------------- brainrender/gui/ui.py | 279 ------------------ brainrender/gui/utils.py | 26 -- brainrender/gui/widgets/__init__.py | 0 brainrender/gui/widgets/actors_list.py | 44 --- brainrender/gui/widgets/add_from_file.py | 80 ----- brainrender/gui/widgets/add_regions.py | 95 ------ brainrender/gui/widgets/screenshot_modal.py | 54 ---- brainrender/gui/widgets/tree.py | 43 --- pyproject.toml | 8 +- tests/test_gui.py | 22 -- 31 files changed, 1 insertion(+), 1695 deletions(-) delete mode 100644 brainrender/gui/__init__.py delete mode 100644 brainrender/gui/app.py delete mode 100644 brainrender/gui/apputils/__init__.py delete mode 100644 brainrender/gui/apputils/actors_control.py delete mode 100644 brainrender/gui/apputils/add_from_file_control.py delete mode 100644 brainrender/gui/apputils/camera_control.py delete mode 100644 brainrender/gui/apputils/regions_control.py delete mode 100644 brainrender/gui/icons/BG_logo_mini.svg delete mode 100644 brainrender/gui/icons/__init__.py delete mode 100644 brainrender/gui/icons/box_dark.svg delete mode 100644 brainrender/gui/icons/box_light.svg delete mode 100644 brainrender/gui/icons/checkedbox_dark.svg delete mode 100644 brainrender/gui/icons/checkedbox_light.svg delete mode 100644 brainrender/gui/icons/down_dark.svg delete mode 100644 brainrender/gui/icons/down_light.svg delete mode 100644 brainrender/gui/icons/eye-slash.svg delete mode 100644 brainrender/gui/icons/eye.svg delete mode 100644 brainrender/gui/icons/right_dark.svg delete mode 100644 brainrender/gui/icons/right_light.svg delete mode 100644 brainrender/gui/style.py delete mode 100644 brainrender/gui/ui.py delete mode 100644 brainrender/gui/utils.py delete mode 100644 brainrender/gui/widgets/__init__.py delete mode 100644 brainrender/gui/widgets/actors_list.py delete mode 100644 brainrender/gui/widgets/add_from_file.py delete mode 100644 brainrender/gui/widgets/add_regions.py delete mode 100644 brainrender/gui/widgets/screenshot_modal.py delete mode 100644 brainrender/gui/widgets/tree.py delete mode 100644 tests/test_gui.py diff --git a/MANIFEST.in b/MANIFEST.in index 4bd89592..f383cb1b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,4 @@ global-include *.svg -include brainrender/gui/icons* recursive-exclude paper * recursive-exclude tests * diff --git a/brainrender/gui/__init__.py b/brainrender/gui/__init__.py deleted file mode 100644 index 41809636..00000000 --- a/brainrender/gui/__init__.py +++ /dev/null @@ -1,37 +0,0 @@ -from qtpy.QtWidgets import QApplication -import sys -import click - -from brainrender.gui.app import App - - -def launch(*args, atlas_name=None, output=None, screenshots_folder=None): - """ - Launches the application - """ - if output is None: - screenshot_kwargs = output - else: - screenshot_kwargs = screenshots_folder - - app = QApplication(sys.argv) - app.setApplicationName("Brainrender GUIs") - ex = App( - *args, atlas_name=atlas_name, screenshots_folder=screenshots_folder - ) - app.aboutToQuit.connect(ex.onClose) - ex.show() - sys.exit(app.exec_()) - - -@click.command() -@click.option("-x", "--axes", is_flag=True, default=False) -@click.option("-a", "--atlas", default=None) -@click.option("-o", "--output", default=None) -def clilaunch(atlas=None, axes=False, output=None): - app = QApplication(sys.argv) - app.setApplicationName("Brainrender GUIs") - ex = App(atlas_name=atlas, axes=axes, screenshots_folder=output) - app.aboutToQuit.connect(ex.onClose) - ex.show() - sys.exit(app.exec_()) diff --git a/brainrender/gui/app.py b/brainrender/gui/app.py deleted file mode 100644 index a87a8568..00000000 --- a/brainrender/gui/app.py +++ /dev/null @@ -1,228 +0,0 @@ -import datetime -from collections import namedtuple - -import vtk.qt -from loguru import logger -from qtpy.QtWidgets import QFrame -from vedo import Plotter - -vtk.qt.QVTKRWIBase = "QGLWidget" -from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor - -import brainrender -from brainrender import Scene -from brainrender.camera import set_camera -from brainrender.gui.apputils.actors_control import ActorsControl -from brainrender.gui.apputils.add_from_file_control import AddFromFile -from brainrender.gui.apputils.camera_control import CameraControl -from brainrender.gui.apputils.regions_control import RegionsControl -from brainrender.gui.ui import UI -from brainrender.gui.widgets.actors_list import update_actors_list -from brainrender.gui.widgets.screenshot_modal import ScreenshotModal - - -class App( - Scene, UI, CameraControl, AddFromFile, RegionsControl, ActorsControl -): - startup = True # some things only run once - actors = {} # stores actors and status - camera_orientation = None # used to manually set camera orientation - - def __init__(self, *args, atlas_name=None, axes=None, **kwargs): - """ - Initialise the qtpy app and the brainrender scene. - - Arguments: - ---------- - - atlas_name: str/None. Name of the brainglobe atlas to use - axes: bool. If true axes are shown in the brainrender render - """ - logger.debug("Creating brainrender GUI") - - # make a vtk widget for the vedo plotter - frame = QFrame() - self.vtkWidget = QVTKRenderWindowInteractor(frame) - - # Get vtkWidget plotter and creates a scene embedded in it - new_plotter = Plotter(qt_widget=self.vtkWidget) - self.scene = Scene( - *args, atlas_name=atlas_name, plotter=new_plotter, **kwargs - ) - - # Initialize parent classes - UI.__init__(self, *args, **kwargs) - CameraControl.__init__(self) - AddFromFile.__init__(self) - RegionsControl.__init__(self) - ActorsControl.__init__(self) - - # Setup brainrender plotter - self.axes = axes - self.atuple = namedtuple("actor", "mesh, is_visible, color, alpha") - - self.setup_scene() - self._update() - self.scene.render() - self.scene._get_inset() - - # Setup widgets functionality - self.actors_list.itemDoubleClicked.connect( - self.actor_list_double_clicked - ) - self.actors_list.clicked.connect(self.actor_list_clicked) - - buttons_funcs = dict( - add_brain_regions=self.open_regions_dialog, - add_from_file=self.add_from_file_object, - add_cells=self.add_from_file_cells, - show_structures_tree=self.toggle_treeview, - take_screenshot=self.take_screenshot, - reset=self.reset_camera, - top=self.move_camera_top, - side1=self.move_camera_side1, - side2=self.move_camera_side2, - front=self.move_camera_front, - ) - - for btn, fun in buttons_funcs.items(): - self.buttons[btn].clicked.connect(fun) - - self.treeView.clicked.connect(self.add_region_from_tree) - - self.alpha_textbox.textChanged.connect(self.update_actor_properties) - self.color_textbox.textChanged.connect(self.update_actor_properties) - - self.startup = False - - def take_screenshot(self): - logger.debug("GUI: taking screenshot") - self._update() - self.scene.plotter.render() - - # Get savename - self.scene.screenshots_folder.mkdir(exist_ok=True) - - savename = str(self.scene.screenshots_folder / "brainrender_gui") - savename += ( - f'_{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}' + ".png" - ) - print(f"\nSaving screenshot at {savename}\n") - self.scene.screenshot(name=savename) - - # show success message - dialog = ScreenshotModal(self, self.palette) - dialog.exec() - - # ------------------------------ Toggle treeview ----------------------------- # - def toggle_treeview(self): - """ - Method for the show structures tree button. - It toggles the visibility of treeView widget - and adjusts the button's text accordingly. - """ - logger.debug("GUI: toggle tree view") - if not self.treeView.isHidden(): - self.buttons["show_structures_tree"].setText( - "Show structures tree" - ) - else: - self.buttons["show_structures_tree"].setText( - "Hide structures tree" - ) - - self.treeView.setHidden(not self.treeView.isHidden()) - - # ------------------------------- Initial setup ------------------------------ # - def setup_scene(self): - """ - Set scene's axes and camera - """ - # Get axes - if self.axes: - self.axes = self._make_axes() - # self.scene.add_actor(ax) - else: - self.axes = None - - # Fix camera - set_camera(self.scene, self.scene.plotter.camera) - - # ---------------------------------- Update ---------------------------------- # - def _update_actors(self): - """ - All actors that are part of the scene are stored - in a dictionary with key as the actor name and - value as a 4-tuple with (Mesh, is_visible, color, alpha). - `is_visible` is a bool that determines if the - actor should be rendered - """ - - for actor in self.scene.actors: - if actor is None: - continue - - try: - if actor.name not in self.actors.keys(): - self.actors[actor.name] = self.atuple( - actor, True, actor.mesh.color(), actor.mesh.alpha() - ) - - if actor.silhouette is not None: - self.scene.plotter.remove(actor.silhouette.mesh) - actor.make_silhouette() - - self.scene.plotter.add(actor.silhouette.mesh) - self.actors[actor.silhouette.name] = self.atuple( - actor.silhouette, - True, - actor.silhouette.mesh.color(), - actor.silhouette.mesh.alpha(), - ) - except AttributeError: - # the Assembly object representing the axes should be ignore - pass - - def _update(self): - """ - Updates the scene's Plotter to add/remove - meshes - """ - - # update meshes - self.scene._apply_style() - - # Get actors to render - self._update_actors() - to_render = [act for act in self.actors.values() if act.is_visible] - - # Set actors look - meshes = [act.mesh.c(act.color).alpha(act.alpha) for act in to_render] - - # Add axes - if self.axes is not None: - meshes.append(self.axes) - - # update actors rendered - self.scene.plotter.show( - *meshes, - mode=0, - bg=brainrender.settings.BACKGROUND_COLOR, - resetcam=self.startup, - zoom=None, - ) - - # Fake a button press to force canvas update - self.scene.plotter.interactor.MiddleButtonPressEvent() - self.scene.plotter.interactor.MiddleButtonReleaseEvent() - - # Update list widget - update_actors_list(self.actors_list, self.actors) - return meshes - - # ----------------------------------- Close ---------------------------------- # - def onClose(self): - """ - Disable the interactor before closing to prevent it from trying to act on a already deleted items - """ - self.vtkWidget.close() diff --git a/brainrender/gui/apputils/__init__.py b/brainrender/gui/apputils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/brainrender/gui/apputils/actors_control.py b/brainrender/gui/apputils/actors_control.py deleted file mode 100644 index 826b297d..00000000 --- a/brainrender/gui/apputils/actors_control.py +++ /dev/null @@ -1,114 +0,0 @@ -import numpy as np -from loguru import logger -from pkg_resources import resource_filename -from qtpy.QtGui import QColor, QIcon - -from brainrender.gui.style import palette -from brainrender.gui.utils import ( - get_alpha_from_string, - get_color_from_string, -) - - -class ActorsControl: - def __init__(self): - """ - Collection of functions to control actors properties - and related widget in the GUI - """ - return - - def update_actor_properties(self): - """ - Called when the text boxes for showing/editing - the selected actor's alpha/color are edited. - This function checks that the values makes sense - and update the atuple of the selected actor. - """ - # Get currently selected actor - aname = self.actors_list.currentItem().text() - logger.debug(f"Updating properties of actor: {aname}") - if aname not in self.actors.keys(): - raise ValueError(f"Actor {aname} not in the actors record") - else: - actor = self.actors[aname] - - # Get color - if not self.color_textbox.text(): - return - color = get_color_from_string(self.color_textbox.text()) - - # Get alpha - alpha = get_alpha_from_string(self.alpha_textbox.text()) - if alpha is None: - return - - # Update actor - try: - self.actors[aname] = self.atuple( - actor.mesh, actor.is_visible, color, alpha - ) - self._update() - except IndexError: # something went wrong with getting of color - self.actors[aname] = actor - return - - def actor_list_double_clicked(self, listitem): - """ - When an item in the actors list is double clicked - it toggles the corresponding actor's visibility - and updates the list widget UI - """ - # Get actor - aname = self.actors_list.currentItem().text() - logger.debug(f"GUI: toggling {aname} visibility") - if aname not in self.actors.keys(): - raise ValueError(f"Actor {aname} not in the actors record") - else: - actor = self.actors[aname] - - # Toggle visibility - self.actors[aname] = self.atuple( - actor.mesh, not actor.is_visible, actor.color, actor.alpha - ) - - # Toggle list item UI - if self.actors[aname].is_visible: - txt = palette["text"] - icon = QIcon(resource_filename("brainrender.gui", "icons/eye.svg")) - else: - txt = palette["primary"] - icon = QIcon( - resource_filename("brainrender.gui", "icons/eye-slash.svg") - ) - rgb = txt.replace(")", "").replace(" ", "").split("(")[-1].split(",") - - listitem.setForeground(QColor(*[int(r) for r in rgb])) - listitem.setIcon(icon) - - # update - self._update() - - def actor_list_clicked(self, index): - """ - When an item of the actors list is clicked - this function loads it's parameters and updates - the text in the alpha/color textboxes. - """ - # Get actor - aname = self.actors_list.currentItem().text() - if aname not in self.actors.keys(): - raise ValueError(f"Actor {aname} not in the actors record") - else: - actor = self.actors[aname] - - self.alpha_textbox.setText(str(actor.alpha)) - - if isinstance(actor.color, np.ndarray): - color = "".join( - [str(round(c, 1)) + " " for c in actor.color] - ).rstrip() - else: - color = actor.color - - self.color_textbox.setText(color) diff --git a/brainrender/gui/apputils/add_from_file_control.py b/brainrender/gui/apputils/add_from_file_control.py deleted file mode 100644 index c84f64bb..00000000 --- a/brainrender/gui/apputils/add_from_file_control.py +++ /dev/null @@ -1,92 +0,0 @@ -from pathlib import Path - -import numpy as np -from loguru import logger -from qtpy.QtWidgets import QFileDialog - -from brainrender.actors import Points -from brainrender.gui.utils import ( - get_alpha_from_string, - get_color_from_string, -) -from brainrender.gui.widgets.add_from_file import AddFromFileWindow - - -class AddFromFile: - def __init__(self): - """ - Collection of functions to load data from files - and add it to the GUI's brainrender Scene. - """ - return - - def __add_from_file(self, fun, name_from_file=True): - """ - General function for selecting, loading - and adding to scene a file. - - Arguments: - ----------- - - fun: function. One of Scene's methods used to add the file's - content to the scene. - name_from_file: bool, optional. If True the actor's name is the name of the files loaded - """ - options = QFileDialog.Options() - # options |= QFileDialog.DontUseNativeDialog - - fname, _ = QFileDialog.getOpenFileName( - self, - "QFileDialog.getOpenFileName()", - "", - "All Files (*)", - options=options, - ) - - if not fname: - return - else: - # Get actor color and alpha - dialog = AddFromFileWindow(self, self.palette) - dialog.exec() - - alpha = get_alpha_from_string(dialog.alpha_textbox.text()) - color = get_color_from_string(dialog.color_textbox.text()) - - # Add actor - act = fun(fname) - if not isinstance(act, (tuple, list)): - act = [act] - - # Edit actor - for actor in act: - actor.name = Path(fname).name - - if color != "default": - actor.mesh.c(color) - - if alpha is not None: - actor.mesh.alpha(alpha) - - # Update - self._update() - - def add_from_file_object(self): - """ - Add to scene from brainrender.stl, .obj and .vtk files. - Method of the corresponding button - """ - logger.debug("GUI: adding mesh (e.g. obj) form file") - self.__add_from_file(self.scene.add) - - def _get_cells_mesh(self, fp): - data = np.load(fp) - return self.scene.add(Points(data)) - - def add_from_file_cells(self): - """ - Add to scene from brainrender.npy files with cell coordinates data. - Method of the corresponding button - """ - logger.debug("GUI: adding CELLS from file") - self.__add_from_file(self._get_cells_mesh) diff --git a/brainrender/gui/apputils/camera_control.py b/brainrender/gui/apputils/camera_control.py deleted file mode 100644 index 2730339b..00000000 --- a/brainrender/gui/apputils/camera_control.py +++ /dev/null @@ -1,47 +0,0 @@ -from loguru import logger - -import brainrender -from brainrender.camera import get_camera_params - - -class CameraControl: - """ - Collection of functions to implement the actions of buttons - aimed at controlling the camera of the brainrender Scene - in the GUI. - """ - - def __init__(self): - return - - def _update_camera(self): - if self.camera_orientation is not None: - camera = self.camera_orientation - self.camera_orientation = None - else: - camera = get_camera_params(scene=self.scene) - - self.scene.render(camera=camera) - self._update() - - logger.debug(f"GUI: resetting camera to: {self.camera_orientation}") - - def reset_camera(self): - self.camera_orientation = brainrender.settings.DEFAULT_CAMERA - self._update_camera() - - def move_camera_front(self): - self.camera_orientation = "frontal" # specify brainrender camera - self._update_camera() - - def move_camera_top(self): - self.camera_orientation = "top" # specify brainrender camera - self._update_camera() - - def move_camera_side1(self): - self.camera_orientation = "sagittal" # specify brainrender camera - self._update_camera() - - def move_camera_side2(self): - self.camera_orientation = "sagittal2" # specify brainrender camera - self._update_camera() diff --git a/brainrender/gui/apputils/regions_control.py b/brainrender/gui/apputils/regions_control.py deleted file mode 100644 index 802af294..00000000 --- a/brainrender/gui/apputils/regions_control.py +++ /dev/null @@ -1,106 +0,0 @@ -from loguru import logger - -import brainrender -from brainrender.gui.utils import ( - get_alpha_from_string, - get_color_from_string, - get_region_actors, -) -from brainrender.gui.widgets.actors_list import remove_from_list -from brainrender.gui.widgets.add_regions import AddRegionsWindow - - -class RegionsControl: - def __init__(self): - """ - Collections of functions to control the - addition of regions meshes to the brainrender - Scene for the GUI - """ - return - - def open_regions_dialog(self): - """ - Opens a QDialog window for inputting - regions to add to the scene - """ - self.regions_dialog = AddRegionsWindow(self, self.palette) - - def add_regions(self, regions, alpha, color): - """ - Called by AddRegionsWindow when it closes. - It adds brain regions to the scene - - Arguments: - ---------- - regions: list of strings with regions acronyms - alpha: str, meshes transparency - color: str, meshes color. If 'atlas' the default colors are used - """ - logger.debug(f"GUI: Adding brain regions: {regions}") - # Get params - alpha = get_alpha_from_string(alpha) - if alpha is None: - alpha = brainrender.DEFAULT_MESH_ALPHA - - color = get_color_from_string(color) - if color == "atlas": - colors = None - else: - colors = color - - # Add brain regions - self.scene.add_brain_region( - *regions, - alpha=alpha, - color=colors, - ) - - # update - self._update() - - def add_region_from_tree(self, val): - """ - When an item on the hierarchy tree is double clicked, the - corresponding mesh is added/removed from the brainrender scene - """ - logger.debug("GUI: adding brain region from tree view") - # Get item - idxs = self.treeView.selectedIndexes() - if idxs: - item = idxs[0] - else: - return - item = item.model().itemFromIndex(val) - - # Get region name - region = str(item.tag).split(" ")[0] - - # Toggle checkbox - if not item._checked: - # item.setCheckState(Qt.Checked) - item._checked = True - else: - # item.setCheckState(Qt.Unchecked) - item._checked = False - - # Add/remove mesh - if get_region_actors(self.scene.actors, region) is None: - # Add region - self.scene.add_brain_region( - region, - ) - else: - # remove regiona and update list - # del get_region_actors(self.scene.actors, region) - del self.actors[region] - remove_from_list(self.actors_list, region) - del self.scene.actors[ - [actor.name for actor in self.scene.actors].index(region) - ] - - # Update hierarchy's item font - item.toggle_active() - - # Update brainrender scene - self._update() diff --git a/brainrender/gui/icons/BG_logo_mini.svg b/brainrender/gui/icons/BG_logo_mini.svg deleted file mode 100644 index d9722c0e..00000000 --- a/brainrender/gui/icons/BG_logo_mini.svg +++ /dev/null @@ -1,102 +0,0 @@ - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/brainrender/gui/icons/__init__.py b/brainrender/gui/icons/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/brainrender/gui/icons/box_dark.svg b/brainrender/gui/icons/box_dark.svg deleted file mode 100644 index 5d638182..00000000 --- a/brainrender/gui/icons/box_dark.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/brainrender/gui/icons/box_light.svg b/brainrender/gui/icons/box_light.svg deleted file mode 100644 index 19b61a11..00000000 --- a/brainrender/gui/icons/box_light.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/brainrender/gui/icons/checkedbox_dark.svg b/brainrender/gui/icons/checkedbox_dark.svg deleted file mode 100644 index 149129a2..00000000 --- a/brainrender/gui/icons/checkedbox_dark.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/brainrender/gui/icons/checkedbox_light.svg b/brainrender/gui/icons/checkedbox_light.svg deleted file mode 100644 index 55cead99..00000000 --- a/brainrender/gui/icons/checkedbox_light.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/brainrender/gui/icons/down_dark.svg b/brainrender/gui/icons/down_dark.svg deleted file mode 100644 index b3b55065..00000000 --- a/brainrender/gui/icons/down_dark.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/brainrender/gui/icons/down_light.svg b/brainrender/gui/icons/down_light.svg deleted file mode 100644 index 2fa46dac..00000000 --- a/brainrender/gui/icons/down_light.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/brainrender/gui/icons/eye-slash.svg b/brainrender/gui/icons/eye-slash.svg deleted file mode 100644 index 3b631a02..00000000 --- a/brainrender/gui/icons/eye-slash.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/brainrender/gui/icons/eye.svg b/brainrender/gui/icons/eye.svg deleted file mode 100644 index bb8d1110..00000000 --- a/brainrender/gui/icons/eye.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/brainrender/gui/icons/right_dark.svg b/brainrender/gui/icons/right_dark.svg deleted file mode 100644 index 3bfa4ce2..00000000 --- a/brainrender/gui/icons/right_dark.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/brainrender/gui/icons/right_light.svg b/brainrender/gui/icons/right_light.svg deleted file mode 100644 index e8de8ebb..00000000 --- a/brainrender/gui/icons/right_light.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/brainrender/gui/style.py b/brainrender/gui/style.py deleted file mode 100644 index 715c84db..00000000 --- a/brainrender/gui/style.py +++ /dev/null @@ -1,198 +0,0 @@ -_themes = { - "dark": { - "folder": "dark", - "background": "rgb(38, 41, 48)", - "foreground": "rgb(65, 72, 81)", - "primary": "rgb(90, 98, 108)", - "secondary": "rgb(134, 142, 147)", - "highlight": "rgb(106, 115, 128)", - "text": "rgb(240, 241, 242)", - "icon": "rgb(209, 210, 212)", - "warning": "rgb(153, 18, 31)", - "current": "rgb(0, 122, 204)", - "syntax_style": "native", - "console": "rgb(0, 0, 0)", - "canvas": "black", - }, - "light": { - "folder": "light", - "background": "rgb(239, 235, 233)", - "foreground": "rgb(214, 208, 206)", - "primary": "rgb(188, 184, 181)", - "secondary": "rgb(150, 146, 144)", - "highlight": "rgb(163, 158, 156)", - "text": "rgb(59, 58, 57)", - "icon": "rgb(107, 105, 103)", - "warning": "rgb(255, 18, 31)", - "current": "rgb(253, 240, 148)", - "syntax_style": "default", - "console": "rgb(255, 255, 255)", - "canvas": "white", - }, -} - -palette = { - "folder": "dark", - "background": "rgb(38, 41, 48)", - "foreground": "rgb(65, 72, 81)", - "primary": "rgb(90, 98, 108)", - "secondary": "rgb(134, 142, 147)", - "highlight": "rgb(106, 115, 128)", - "text": "rgb(240, 241, 242)", - "icon": "rgb(209, 210, 212)", - "warning": "rgb(153, 18, 31)", - "current": "rgb(0, 122, 204)", - "syntax_style": "native", - "console": "rgb(0, 0, 0)", - "canvas": "black", -} - -style = """ -QWidget#LeftNavbar { - background-color: BGCOLOR; - border: 2px solid TXTCOLOR; - border-radius: 24px; - margin: 12px 12px; - padding: 24px 12px; -} -QWidget#RightNavbar { - background-color: BGCOLOR; - margin: 12px 12px; - padding: 24px 12px; -} -QWidget#MainWidget { - background-color: BGCOLOR; - padding: 48px; -} - -QWidget#ScreenshotButtonLayout{ - border-right: 2px solid TXTCOLOR; - max-width: 350px; -} - - -QVTKRenderWindowInteractor{ - border-radius: 12px; - width: 200px; -} - -QPushButton { - background-color: FGCOLOR; - color: TXTCOLOR; - border-radius: 8px; - padding: 6px; - font-size: 14pt; - margin: 4px 34px; - min-width: 50px; - -} -QPushButton:hover { - border: 1px solid TXTCOLOR; -} - - -QLabel { - color: TXTCOLOR; - font-size: 16pt; - font-weight: 700; - margin: 12px 24px; -} -QLabel#PopupLabel { - color: TXTCOLOR; - font-size: 14pt; - font-weight: 400; - margin: 12px; -} -QLabel#PropertyName { - font-size: 14pt; - font-weight: 500; - margin: 0px 24px; -} -QLabel#LabelWithBorder { - border-top: 1px solid TXTCOLOR; - padding-top: 12px; -} - -QListWidget#actors_list { - background-color: FGCOLOR; - color: TXTCOLOR; - border-radius: 8px; - padding: 6px; - font-size: 14pt; - margin: 4px 34px; -} - -QLineEdit { - background-color: FGCOLOR; - color: TXTCOLOR; - border-radius: 8px; - padding: 6px; - font-size: 12pt; - height: 48px; - min-width: 600px; - margin: 4px 34px; - width: 80% -} -QLineEdit#Property { - min-width: none; - height: 32px; - padding: 4px 6px; -} -QDialog { - background-color: BGCOLOR; -} -QPushButton#RegionsButton { - width: 60%; -} - -""" - - -# for ref: https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview -tree_css = """ -QTreeView { - background-color: BGCOLOR; - border-radius: 12px; - padding: 20px 12px; -} -QTreeView::indicator:checked { - image: url(CHECKED_IMG); -} -QTreeView::indicator:unchecked { - image: url(UNCHECKED_IMG); -} - - -QTreeView::branch:has-children:!has-siblings:closed,QTreeView::branch:closed:has-children:has-siblings { - border-image: none; - image: url(CLOSED_IMG); -} -QTreeView::branch:open:has-children:!has-siblings,QTreeView::branch:open:has-children:has-siblings { - border-image: none; - image: url(OPENED_IMG); -} - -""" - - -def update_css(css, palette): - """ - Updates a CSS string with values - from the palette chosen. - """ - - def path(raw_path): - return raw_path.replace("\\", "/") - - css = css.replace("FGCOLOR", palette["foreground"]) - css = css.replace("BGCOLOR", palette["background"]) - css = css.replace("TXTCOLOR", palette["text"]) - css = css.replace("HIGHLIGHT", palette["highlight"]) - - css = css.replace("CLOSED_IMG", path(palette["branch_closed_img"])) - css = css.replace("OPENED_IMG", path(palette["branch_opened_img"])) - - css = css.replace("UNCHECKED_IMG", path(palette["unchecked_img"])) - css = css.replace("CHECKED_IMG", path(palette["checked_img"])) - - return css diff --git a/brainrender/gui/ui.py b/brainrender/gui/ui.py deleted file mode 100644 index 1c977cf1..00000000 --- a/brainrender/gui/ui.py +++ /dev/null @@ -1,279 +0,0 @@ -from pkg_resources import resource_filename -from qtpy import QtGui -from qtpy.QtCore import Qt -from qtpy.QtGui import QStandardItemModel -from qtpy.QtWidgets import ( - QHBoxLayout, - QLabel, - QLineEdit, - QListWidget, - QMainWindow, - QPushButton, - QSplitter, - QTreeView, - QVBoxLayout, - QWidget, -) - -from brainrender.gui.style import _themes, style, tree_css, update_css -from brainrender.gui.widgets.tree import StandardItem - - -class UI(QMainWindow): - buttons = {} - - right_navbar_button_names = [ - "add brain regions", - "add cells", - "add from file", - ] - - central_column_button_names = [ - "take screenshot", - "reset", - "top", - "side1", - "side2", - "front", - ] - - def __init__(self, theme="dark", **kwargs): - super().__init__() - - # Get palette - self.palette = _themes[theme] - self.theme = theme - - # set the title and icon of main window - self.setWindowTitle("BRAINGLOBE - brainrender GUI") - - logo_path = resource_filename( - "brainrender.gui.icons", "BG_logo_mini.svg" - ) - self.setWindowIcon(QtGui.QIcon(logo_path)) - - # set the size of window - self.Width = 3000 - self.height = int(0.618 * self.Width) - self.resize(self.Width, self.height) - - # Create UI - self.get_icons() - self.initUI() - self.setStyleSheet(update_css(style, self.palette)) - - def get_icons(self): - """ - Gets the correct path to the icons - depending on the theme chosen - """ - self.palette["branch_closed_img"] = resource_filename( - "brainrender.gui.icons", f"right_{self.theme}.svg" - ) - self.palette["branch_opened_img"] = resource_filename( - "brainrender.gui.icons", f"down_{self.theme}.svg" - ) - self.palette["checked_img"] = resource_filename( - "brainrender.gui.icons", f"checkedbox_{self.theme}.svg" - ) - self.palette["unchecked_img"] = resource_filename( - "brainrender.gui.icons", f"box_{self.theme}.svg" - ) - - def make_left_navbar(self): - """ - Creates the structures tree hierarchy widget and populates - it with structures names from the brainglobe-api's Atlas.hierarchy - tree view. - """ - # Create QTree widget - treeView = QTreeView() - treeView.setExpandsOnDoubleClick(False) - treeView.setHeaderHidden(True) - treeView.setStyleSheet(update_css(tree_css, self.palette)) - treeView.setWordWrap(False) - - treeModel = QStandardItemModel() - rootNode = treeModel.invisibleRootItem() - - # Add element's hierarchy - tree = self.scene.atlas.hierarchy - items = {} - for n, node in enumerate(tree.expand_tree()): - # Get Node info - node = tree.get_node(node) - if node.tag in ["VS", "fiber tracts"]: - continue - - # Get brainregion name - name = self.scene.atlas._get_from_structure( - node.identifier, "name" - ) - - # Create Item - item = StandardItem( - name, - node.tag, - tree.depth(node.identifier), - self.palette["text"], - ) - - # Get/assign parents - parent = tree.parent(node.identifier) - if parent is not None: - if parent.identifier not in items.keys(): - continue - else: - items[parent.identifier].appendRow(item) - - # Keep track of added nodes - items[node.identifier] = item - if n == 0: - root = item - - # Finish up - rootNode.appendRow(root) - treeView.setModel(treeModel) - treeView.expandToDepth(2) - self.treeView = treeView - - return treeView - - def make_right_navbar(self): - """ - Creates the widgets in the right navbar. - """ - # make layout - layout = QVBoxLayout() - - # Add label - layout.addWidget(QLabel("Add actors")) - - # Add buttons - for bname in self.right_navbar_button_names: - btn = QPushButton(bname.capitalize(), self) - btn.setObjectName(bname.replace(" ", "_")) - self.buttons[bname.replace(" ", "_")] = btn - layout.addWidget(btn) - - # Add label - lbl = QLabel("Actors") - lbl.setObjectName("LabelWithBorder") - layout.addWidget(lbl) - - # add list widget - self.actors_list = QListWidget() - self.actors_list.setObjectName("actors_list") - layout.addWidget(self.actors_list) - - # Add label - lbl = QLabel("Actor properties") - lbl.setObjectName("LabelWithBorder") - layout.addWidget(lbl) - - # Actor Alpha - alphalabel = QLabel("Alpha") - alphalabel.setObjectName("PropertyName") - self.alpha_textbox = QLineEdit(self) - self.alpha_textbox.setObjectName("Property") - layout.addWidget(alphalabel) - layout.addWidget(self.alpha_textbox) - - # Actor Color - colorlabel = QLabel("Color") - colorlabel.setObjectName("PropertyName") - self.color_textbox = QLineEdit(self) - self.color_textbox.setObjectName("Property") - layout.addWidget(colorlabel) - layout.addWidget(self.color_textbox) - - # Add label - lbl = QLabel("Show structures tree") - lbl.setObjectName("LabelWithBorder") - layout.addWidget(lbl) - - btn = QPushButton("Show structures tree", self) - self.buttons[btn.text().lower().replace(" ", "_")] = btn - layout.addWidget(btn) - - # set spacing - layout.addStretch(5) - layout.setSpacing(20) - - # make widget - widget = QWidget() - widget.setObjectName("RightNavbar") - widget.setLayout(layout) - - return widget - - def make_central_column(self): - """ - Creates vtkWidget for the vedo plotter and a few - useful buttons, for the central part of the GUI - """ - # Create layout, add canvas and buttons - layout = QVBoxLayout() - layout.addWidget(self.vtkWidget) - - # Make buttons - boxes = [QHBoxLayout(), QHBoxLayout()] - for n, bname in enumerate(self.central_column_button_names): - btn = QPushButton(bname.capitalize(), self) - btn.setObjectName(bname.replace(" ", "_")) - self.buttons[bname.replace(" ", "_")] = btn - - if n == 0: - boxes[0].addWidget(btn) - else: - boxes[1].addWidget(btn) - - hlayout = QHBoxLayout() - - widget = QWidget() - widget.setLayout(boxes[0]) - widget.setObjectName("ScreenshotButtonLayout") - hlayout.addWidget(widget) - - widget = QWidget() - widget.setLayout(boxes[1]) - hlayout.addWidget(widget) - - widget = QWidget() - widget.setObjectName("CentralColumn_buttons") - widget.setLayout(hlayout) - - layout.addWidget(widget) - - # make widget - widget = QWidget() - widget.setObjectName("CentralColumn") - widget.setLayout(layout) - - return widget - - def initUI(self): - """ - Define UI elements of the app's main window - """ - # Create navbars - self.treeView = self.make_left_navbar() - - # Make overall layout - main_layout = QHBoxLayout() - - splitter = QSplitter(Qt.Horizontal) - splitter.addWidget(self.treeView) - splitter.addWidget(self.make_central_column()) - splitter.addWidget(self.make_right_navbar()) - - splitter.setSizes([200, 700, 10]) - main_layout.addWidget(splitter) - - self.treeView.setHidden(True) - - # Create main window widget - main_widget = QWidget() - main_widget.setObjectName("MainWidget") - main_widget.setLayout(main_layout) - self.setCentralWidget(main_widget) diff --git a/brainrender/gui/utils.py b/brainrender/gui/utils.py deleted file mode 100644 index e1b9b806..00000000 --- a/brainrender/gui/utils.py +++ /dev/null @@ -1,26 +0,0 @@ -import numpy as np - - -def get_region_actors(actors, region): - acts = [act for act in actors if act.name == region] - - if acts: - return acts[0] - else: - return None - - -def get_color_from_string(string): - try: - rgb = string.replace("[", "").replace("]", "") - color = np.array([float(c) for c in rgb.split(" ")]) - return color - except ValueError: - return string.lower() - - -def get_alpha_from_string(string): - try: - return float(string) - except ValueError: - return None diff --git a/brainrender/gui/widgets/__init__.py b/brainrender/gui/widgets/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/brainrender/gui/widgets/actors_list.py b/brainrender/gui/widgets/actors_list.py deleted file mode 100644 index fbf24807..00000000 --- a/brainrender/gui/widgets/actors_list.py +++ /dev/null @@ -1,44 +0,0 @@ -from loguru import logger -from pkg_resources import resource_filename -from qtpy.QtGui import QIcon - - -def get_in_alist(qlist): - """ - Gets items in the actor list - """ - items = [] - for index in range(qlist.count()): - items.append(qlist.item(index).text()) - return items - - -def update_actors_list(qlist, actorsdict): - """ - Adds missing entries in the actors list - """ - listed = get_in_alist(qlist) - - # Add items to list - for actor in actorsdict.keys(): - if actor not in listed: - qlist.insertItem(qlist.count() + 1, actor) - - item = qlist.item(qlist.count() - 1) - item.setIcon( - QIcon(resource_filename("brainrender.gui", "icons/eye.svg")) - ) - - -def remove_from_list(qlist, aname): - """ - Removes an entry from the actors list - """ - logger.debug(f"GUI: removing {aname} from actors list") - if aname not in get_in_alist(qlist): - raise ValueError( - f"Attempting to remove {aname} from list, but {aname} not in list." - ) - else: - idx = [n for n, a in enumerate(get_in_alist(qlist)) if a == aname][0] - qlist.takeItem(idx) diff --git a/brainrender/gui/widgets/add_from_file.py b/brainrender/gui/widgets/add_from_file.py deleted file mode 100644 index c5805a3c..00000000 --- a/brainrender/gui/widgets/add_from_file.py +++ /dev/null @@ -1,80 +0,0 @@ -from qtpy.QtWidgets import QDialog, QLabel, QLineEdit, QPushButton, QVBoxLayout - -from brainrender.gui.style import style, update_css - - -class AddFromFileWindow(QDialog): - left = 250 - top = 250 - width = 400 - height = 300 - - label_msg = ( - "Write the acronyms of brainregions " - + "you wish to add.\n[as 'space' separated strings (e.g.: STN TH)]" - ) - - def __init__(self, main_window, palette): - """ - Creates a new window for user to input - which regions to add to scene. - - Arguments: - ---------- - - main_window: reference to the App's main window - palette: main_window's palette, used to style widgets - """ - super().__init__() - self.setWindowTitle("Add brain regions") - self.ui() - self.main_window = main_window - self.setStyleSheet(update_css(style, palette)) - - def ui(self): - """ - Define UI's elements - """ - self.setGeometry(self.left, self.top, self.width, self.height) - - layout = QVBoxLayout() - - # Alpha - alpha_label = QLabel(self) - alpha_label.setObjectName("PopupLabel") - alpha_label.setText("Alpha") - - self.alpha_textbox = QLineEdit(self) - self.alpha_textbox.setText(str(1.0)) - - # Color - color_label = QLabel(self) - color_label.setObjectName("PopupLabel") - color_label.setText("Color") - - self.color_textbox = QLineEdit(self) - self.color_textbox.setText("default") - - # Create a button in the window - self.button = QPushButton("Ok", self) - self.button.clicked.connect(self.on_click) - self.button.setObjectName("RegionsButton") - - layout.addWidget(alpha_label) - layout.addWidget(self.alpha_textbox) - - layout.addWidget(color_label) - layout.addWidget(self.color_textbox) - - layout.addWidget(self.button) - - self.setLayout(layout) - self.show() - - def on_click(self): - """ - On click or 'Enter' get the regions - from the input and call the add_regions - method of the main window - """ - self.close() diff --git a/brainrender/gui/widgets/add_regions.py b/brainrender/gui/widgets/add_regions.py deleted file mode 100644 index 1570ae61..00000000 --- a/brainrender/gui/widgets/add_regions.py +++ /dev/null @@ -1,95 +0,0 @@ -from qtpy.QtWidgets import QDialog, QLabel, QLineEdit, QPushButton, QVBoxLayout - -from brainrender.gui.style import style, update_css - - -class AddRegionsWindow(QDialog): - left = 250 - top = 250 - width = 400 - height = 300 - - label_msg = ( - "Write the acronyms of brainregions " - + "you wish to add.\n[as 'space' separated strings (e.g.: STN TH)]" - ) - - def __init__(self, main_window, palette): - """ - Creates a new window for user to input - which regions to add to scene. - - Arguments: - ---------- - - main_window: reference to the App's main window - palette: main_window's palette, used to style widgets - """ - super().__init__() - self.setWindowTitle("Select options") - self.ui() - self.main_window = main_window - self.setStyleSheet(update_css(style, palette)) - - def ui(self): - """ - Define UI's elements - """ - self.setGeometry(self.left, self.top, self.width, self.height) - - layout = QVBoxLayout() - - # Regions - label = QLabel(self) - label.setObjectName("PopupLabel") - label.setText(self.label_msg) - - self.textbox = QLineEdit(self) - - # Alpha - alpha_label = QLabel(self) - alpha_label.setObjectName("PopupLabel") - alpha_label.setText("Alpha") - - self.alpha_textbox = QLineEdit(self) - self.alpha_textbox.setText(str(1.0)) - - # Color - color_label = QLabel(self) - color_label.setObjectName("PopupLabel") - color_label.setText("Color") - - self.color_textbox = QLineEdit(self) - self.color_textbox.setText("atlas") - - # Create a button in the window - self.button = QPushButton("Add regions", self) - self.button.clicked.connect(self.on_click) - self.button.setObjectName("RegionsButton") - - layout.addWidget(label) - layout.addWidget(self.textbox) - - layout.addWidget(alpha_label) - layout.addWidget(self.alpha_textbox) - - layout.addWidget(color_label) - layout.addWidget(self.color_textbox) - - layout.addWidget(self.button) - - self.setLayout(layout) - self.show() - - def on_click(self): - """ - On click or 'Enter' get the regions - from the input and call the add_regions - method of the main window - """ - regions = self.textbox.text().split(" ") - self.main_window.add_regions( - regions, self.alpha_textbox.text(), self.color_textbox.text() - ) - - self.close() diff --git a/brainrender/gui/widgets/screenshot_modal.py b/brainrender/gui/widgets/screenshot_modal.py deleted file mode 100644 index 637b8b43..00000000 --- a/brainrender/gui/widgets/screenshot_modal.py +++ /dev/null @@ -1,54 +0,0 @@ -from qtpy import QtCore -from qtpy.QtWidgets import QDialog, QLabel, QVBoxLayout - -from brainrender.gui.style import style, update_css - - -class ScreenshotModal(QDialog): - left = 250 - top = 250 - width = 400 - height = 120 - - def __init__(self, main_window, palette): - """ - Creates a new window for user to input - which regions to add to scene. - - Arguments: - ---------- - - main_window: reference to the App's main window - palette: main_window's palette, used to style widgets - """ - super().__init__() - self.setWindowTitle("Add brain regions") - self.ui() - self.main_window = main_window - self.setStyleSheet(update_css(style, palette)) - - # Start timer to autoclose - self.timer = QtCore.QTimer(self) - self.timer.setInterval(1500) - self.timer.timeout.connect(self.close) - self.timer.start() - - def ui(self): - """ - Define UI's elements - """ - self.setGeometry(self.left, self.top, self.width, self.height) - - layout = QVBoxLayout() - - label = QLabel(self) - - label.setStyleSheet("font-size: 18pt; font-weight: 700;") - - label.setObjectName("PopupLabel") - label.setText("Screenshot saved") - layout.addWidget(label) - - self.setLayout(layout) - self.setModal(True) - self.show() diff --git a/brainrender/gui/widgets/tree.py b/brainrender/gui/widgets/tree.py deleted file mode 100644 index 8f736fb7..00000000 --- a/brainrender/gui/widgets/tree.py +++ /dev/null @@ -1,43 +0,0 @@ -from qtpy.QtGui import QColor, QFont, QStandardItem - - -class StandardItem(QStandardItem): - def __init__(self, txt="", tag=None, depth=0, color=None): - """ - Items in the tree list with some - extended functionality to specify/update - their look. - """ - super().__init__() - self.depth = depth # depth in the hierarchy structure - self.tag = tag - - self._checked = False - - # Set font color/size - self.toggle_active() - - # Set text - self.setEditable(False) - rgb = color.replace(")", "").replace(" ", "").split("(")[-1].split(",") - self.setForeground(QColor(*[int(r) for r in rgb])) - self.setText(txt) - - # Set checkbox - # self.setFlags( - # self.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable - # ) - # self.setCheckState(Qt.Unchecked) - - def toggle_active(self): - """ - When a mesh corresponding to the item's region - gets rendered, change the font to bold - to highlight the fact. - """ - fnt = QFont("Roboto", 14) - if self._checked: - fnt.setBold(True) - else: - fnt.setBold(False) - self.setFont(fnt) diff --git a/pyproject.toml b/pyproject.toml index b2310f30..def0ba60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,6 @@ dependencies = [ "bg-atlasapi>=1.0.0", "tables", "pyinspect>=0.0.8", - "qtpy", "myterial", "loguru", ] @@ -50,7 +49,6 @@ user_support = "https://github.com/brainglobe/brainrender/issues" dev = [ "pytest", "pytest-cov", - "pytest-qt", "coverage", "tox", "black", @@ -58,14 +56,10 @@ dev = [ "pre-commit", "ruff", "setuptools_scm", - "pyqt5", "imio", ] nb = ["jupyter", "k3d"] - pyside2= ["PySide2"] - pyqt5= ["PyQt5"] -[project.scripts] -brainrender-gui = "brainrender.gui.__init__:clilaunch" + [build-system] requires = [ diff --git a/tests/test_gui.py b/tests/test_gui.py deleted file mode 100644 index 7f037d35..00000000 --- a/tests/test_gui.py +++ /dev/null @@ -1,22 +0,0 @@ -# from qtpy import QtCore -import pytest - -from brainrender.gui.app import App - - -@pytest.mark.local -def test_simple_launch(qtbot): - window = App() - qtbot.addWidget(window) - window.show() - - -# @pytest.mark.local -# def test_toggle_treeview(qtbot): -# window = App() -# qtbot.addWidget(window) -# window.show() -# # qtbot.wait_for_window_shown(window) -# qtbot.mouseClick( -# window.buttons["show_structures_tree"], QtCore.Qt.LeftButton -# )