diff --git a/pymapmanager/interface2/mainMenus.py b/pymapmanager/interface2/mainMenus.py index 6a4ad18e..da0c8dcd 100644 --- a/pymapmanager/interface2/mainMenus.py +++ b/pymapmanager/interface2/mainMenus.py @@ -265,6 +265,8 @@ def _onAboutMenuAction(self, name): def _refreshEditMenu(self): """Manage undo/redo menus. + + 20241011, redo is always off. """ self.editMenu.clear() @@ -300,7 +302,8 @@ def _refreshEditMenu(self): redoAction = QtWidgets.QAction("Redo " + nextRedo, self.getApp()) redoAction.setCheckable(False) # setChecked is True by default? redoAction.setShortcut("Shift+Ctrl+Z") - redoAction.setEnabled(enableRedo) + # redoAction.setEnabled(enableRedo) + redoAction.setEnabled(False) redoAction.triggered.connect(self.getApp()._redo_action) self.editMenu.addAction(redoAction) @@ -437,8 +440,8 @@ def _refreshOpenRecent(self): self.openRecentMenu.clear() - # add files - for recentFile in configDict.getRecentStacks(): + # add recent mmap files + for recentFile in configDict.getRecentMaps(): loadFileAction = QtWidgets.QAction(recentFile, self.getApp()) loadFileAction.triggered.connect( partial(self.getApp().loadStackWidget, recentFile) @@ -446,16 +449,16 @@ def _refreshOpenRecent(self): self.openRecentMenu.addAction(loadFileAction) - self.openRecentMenu.addSeparator() + # self.openRecentMenu.addSeparator() - # add folders - for recentFolder in configDict.getRecentMaps(): - loadFolderAction = QtWidgets.QAction(recentFolder, self.getApp()) - loadFolderAction.triggered.connect( - partial(self.getApp().loadMapWidget, recentFolder) - ) + # add recent folders + # for recentFolder in configDict.getRecentMaps(): + # loadFolderAction = QtWidgets.QAction(recentFolder, self.getApp()) + # loadFolderAction.triggered.connect( + # partial(self.getApp().loadMapWidget, recentFolder) + # ) - self.openRecentMenu.addAction(loadFolderAction) + # self.openRecentMenu.addAction(loadFolderAction) def _refreshAnalysisParameters(self): """ diff --git a/pymapmanager/interface2/openFirstWindow.py b/pymapmanager/interface2/openFirstWindow.py index bde1a8d2..556736d5 100644 --- a/pymapmanager/interface2/openFirstWindow.py +++ b/pymapmanager/interface2/openFirstWindow.py @@ -97,37 +97,27 @@ def _makeRecentTable(self, pathList : List[str], headerStr = ''): myTableWidget.setRowHeight(idx, _rowHeight + int(.7 * _rowHeight)) return myTableWidget - - def _old_on_recent_stack_click(self, rowIdx : int): - """On double-click, open a file and close self. - """ - path = self.recentStackList[rowIdx] - logger.info(f'rowId:{rowIdx} path:{path}') - - # abj: Changed this to check if it is a directory instead of a file - # if os.path.isfile(path): - if os.path.isdir(path): - self.getApp().loadStackWidget(path) - else: - logger.error(f'did not find path: {path}') def _on_recent_map_click(self, rowIdx : int): - """On double-click, open a folder and close self. + """On double-click, open a mmap and close self. """ path = self.recentMapList[rowIdx] logger.info(f'rowId:{rowIdx} path:{path}') - if os.path.isdir(path): - self.getApp().loadMapWidget(path) + # if os.path.isdir(path): + if os.path.isfile(path): + self.getApp().loadStackWidget(path) else: - logger.error(f'did not find path: {path}') + logger.error(f'did not find dir path: {path}') def _on_open_button_click(self, name : str): logger.info(name) if name == 'Open...': self._app.loadStackWidget() - elif name == 'Open Folder...': - self._app.loadMapWidget() + + # TODO: implement this + # elif name == 'Open Folder...': + # self._app.loadFolder() # load a folder of mmap def _buildUI(self): # typical wrapper for PyQt, we can't use setLayout(), we need to use setCentralWidget() @@ -152,22 +142,22 @@ def _buildUI(self): name = 'Open...' aButton = QtWidgets.QPushButton(name) - aButton.setFixedSize(QtCore.QSize(200, 60)) - aButton.setToolTip('Open an image.') + aButton.setFixedSize(QtCore.QSize(180, 40)) + aButton.setToolTip('Open a tif or mmap file.') aButton.clicked.connect(partial(self._on_open_button_click, name)) hBoxLayout.addWidget(aButton, alignment=QtCore.Qt.AlignLeft) - name = 'Open Map...' + name = 'Open Folder...' aButton = QtWidgets.QPushButton(name) - aButton.setFixedSize(QtCore.QSize(200, 60)) - aButton.setToolTip('Open a map.') + aButton.setFixedSize(QtCore.QSize(180, 40)) + aButton.setToolTip('Open a folder of mmap files.') aButton.clicked.connect(partial(self._on_open_button_click, name)) hBoxLayout.addWidget(aButton, alignment=QtCore.Qt.AlignLeft) name = 'Drag and Drop' aButton = DragAndDropWidget(name, self._app) - aButton.setFixedSize(QtCore.QSize(200, 60)) - aButton.setToolTip('Drag and Drop Tif File.') + aButton.setFixedSize(QtCore.QSize(180, 40)) + aButton.setToolTip('Drag and drop a tif or mmap file.') # aButton.clicked.connect(partial(self._on_open_button_click, name)) hBoxLayout.addWidget(aButton, alignment=QtCore.Qt.AlignLeft) diff --git a/pymapmanager/interface2/preferences.py b/pymapmanager/interface2/preferences.py index 3745bcbd..9aaaeeda 100644 --- a/pymapmanager/interface2/preferences.py +++ b/pymapmanager/interface2/preferences.py @@ -34,13 +34,13 @@ def getStackWindowGeometry(self) -> List[int]: theRet = [x, y, width, height] return theRet - def getMostRecentStack(self): - return self.configDict["mostRecentStack"] + # def getMostRecentStack(self): + # return self.configDict["mostRecentStack"] - def getRecentStacks(self): - return self.configDict["recentStacks"] + # def getRecentStacks(self): + # return self.configDict["recentStacks"] - def getMostRecentMap(self): + def getMostRecentMap(self) -> str: return self.configDict["mostRecentMap"] def getRecentMaps(self): @@ -62,32 +62,16 @@ def __getitem__(self, key): return return self._configDict[key] - def _old_addStackPath(self, stackPath : str): - """Add a single timepoint stack. - - Similar to addMapPath. - """ - - if stackPath not in self.configDict["recentStacks"]: - self.configDict["recentStacks"].append(stackPath) - # limit list to last _maxNumUndo - self.configDict["recentStacks"] = self.configDict["recentStacks"][ - -self._maxRecent : - ] - - # always set as the most recent file - self.configDict["mostRecentStack"] = stackPath - self.save() def addMapPath(self, mapPath : str): - """Add a map path. - Similar to addMapPath. + """Add a map path to recent maps """ if mapPath not in self.configDict["recentMaps"]: self.configDict["recentMaps"].append(mapPath) - # limit list to last _maxNumUndo + + # reduce/limit list to last _maxRecent self.configDict["recentMaps"] = self.configDict["recentMaps"][-self._maxRecent :] # always set as the most recent file @@ -168,8 +152,8 @@ def getDefaults(self) -> dict: configDict["version"] = self._version configDict["theme"] = 'dark' # in ['dark', 'light', 'auto'] - configDict["recentStacks"] = [] - configDict["mostRecentStack"] = "" + # configDict["recentStacks"] = [] + # configDict["mostRecentStack"] = "" configDict["recentMaps"] = [] configDict["mostRecentMap"] = "" @@ -185,3 +169,6 @@ def getDefaults(self) -> dict: configDict['logLevel'] = 'INFO' return configDict + + def getRecentMapsDataframe(self): + pass diff --git a/pymapmanager/interface2/pyMapManagerApp2.py b/pymapmanager/interface2/pyMapManagerApp2.py index a7d1952a..1959dfb1 100644 --- a/pymapmanager/interface2/pyMapManagerApp2.py +++ b/pymapmanager/interface2/pyMapManagerApp2.py @@ -149,6 +149,8 @@ def openWidgetFromPath(self, path : str): """Open a stack or map from path. This opens a TimeSeriesCore and then a stack or map widget + + Returns a stack widget (tp==1) or a map widget (tp>1) """ if path not in self._widgetDictList.keys(): logger.info(f'loading widget path:{path}') @@ -177,6 +179,9 @@ def openWidgetFromPath(self, path : str): self._widgetDictList[path] = _aWidget + # add to recent opened maps + self._app.getConfigDict().addMapPath(path) + return self._widgetDictList[path] def showMapOrStack(self, path): @@ -446,15 +451,6 @@ def _showAnalysisParameters(self): self.apWidget = AnalysisParamWidget(stackWidget=_frontWidget, pmmApp=self) self.apWidget.show() - # if len(self._stackWidgetDict) > 0: - # for key in self._stackWidgetDict.keys(): - # # looping through every path in stackWidgetDict - # # key = path of current stack - # currentStackWidget = self._stackWidgetDict[key] - - # self.apWidget = AnalysisParamWidget(stackWidget=currentStackWidget, pmmApp=self) - # self.apWidget.show() - def _undo_action(self): self.getFrontWindow().emitUndoEvent() @@ -466,28 +462,10 @@ def toggleMapWidget(self, path : str, visible : bool): """Show/hide a map widget. """ if path not in self._mapWidgetDict.keys(): - logger.warning(f'did not find in keys') + logger.warning(f'did not find path:{path} in keys: {self._mapWidgetDict.keys()}') return self._mapWidgetDict[path].setVisible(visible) - def _old_closeMapWindow(self, mapWidget): - """Remove theWindow from self._windowList. - """ - logger.info(' remove _mapWidgetDict window from app list of windows') - mapPath = mapWidget.getMap().path - popThisKey = None - for pathKey in self._mapWidgetDict.keys(): - if pathKey == mapPath: - popThisKey = pathKey - - if popThisKey is not None: - self._mapWidgetDict.pop(popThisKey, None) - - # check if there are any more windows and show load window - if len(self._stackWidgetDict.keys()) == 0 and \ - len(self._mapWidgetDict.keys()) == 0: - self._openFirstWindow.show() - def showMapOrStack(self, path): """Show an already opened map or stack widget. @@ -495,19 +473,6 @@ def showMapOrStack(self, path): """ self._openWidgetList.showMapOrStack(path) return - - logger.info(path) - if path in self._stackWidgetDict.keys(): - self._stackWidgetDict[path].show() - self._stackWidgetDict[path].raise_() - self._stackWidgetDict[path].activateWindow() - elif path in self._mapWidgetDict.keys(): - self._mapWidgetDict[path].show() - self._mapWidgetDict[path].raise_() - self._mapWidgetDict[path].activateWindow() - else: - logger.warning('did not find opened map or stack with path') - logger.warning(f' {path}') def getScreenGrid(self, numItems : int, itemsPerRow : int) -> List[List[int]]: """Get screen coordiates for a grid of windows. @@ -548,120 +513,11 @@ def getScreenGrid(self, numItems : int, itemsPerRow : int) -> List[List[int]]: currentTop += windowHeight + vSpace return posList - - def _old_loadMapWidget(self, path): - """Load the main map widget from a path. - """ - if path in self._mapWidgetDict.keys(): - self._mapWidgetDict[path].show() - else: - # load map and make widget - logger.info(f'loading mmMap from path: {path}') - _map = pmm.mmMap(path) - logger.info(f' {_map}') - _mapWidget = pmm.interface2.mapWidgets.mapWidget(_map) - self._mapWidgetDict[path] = _mapWidget - - self._mapWidgetDict[path].show() - self._mapWidgetDict[path].raise_() - self._mapWidgetDict[path].activateWindow() - - # always hide the open first window - self._openFirstWindow.hide() - - # add to recent opened windows - self.getConfigDict().addMapPath(path) - - return self._mapWidgetDict[path] - - # def loadTifFile2(self, path : str): - # import pandas as pd - # from mapmanagercore import MapAnnotations, MultiImageLoader - # from pymapmanager import stack - - # # check that path exists and is .tif file - # if not os.path.isfile(path): - # logger.warning(f'file not found: {path}') - # return - # _ext = os.path.splitext(path)[1] - # if _ext != '.tif': - # logger.warning(f'can only load files with .tif extension, got extension "{_ext}"') - # return - - # loader = MultiImageLoader() - # loader.read(path, channel=0) - - # map = MapAnnotations(loader.build(), - # lineSegments=pd.DataFrame(), - # points=pd.DataFrame()) - - # logger.info(f'map from tif file is {map}') - - # # make a stack - # aStack = stack(zarrMap=map) - # aStack.header['numChannels'] = 1 - - # print(aStack) - - # self.stackWidgetFromStack(aStack) - - # abj - def _old_loadTifFile(self, path : str): - """Load a stack from tif from a path. - Only happens on first load/ drag and drop - Create stackwidget/ mmap from tif file - - Parameters - ---------- - path : str - Full path to tif file - """ - from mapmanagercore import MapAnnotations, MultiImageLoader - from mapmanagercore.lazy_geo_pandas import LazyGeoFrame - from mapmanagercore.schemas import Segment, Spine - - loader = MultiImageLoader() - # path = "C:\\Users\\johns\\Documents\\GitHub\\PyMapManager-Data\\one-timepoint\\rr30a_s0_ch1.tif" - - try: # Check if path is a tif file - # TODO: detect channel, move channel to parameter - loader.read(path, channel=0) - logger.info("loading tif file!") - except Exception as e: # else return error message - logger.info(f"Exeception when reading tif file: {e}") - return - import pandas as pd - import geopandas - lineSegments = geopandas.GeoDataFrame() - points = geopandas.GeoDataFrame() - - - # Might no be necessary, example.ipynb works with empty geodataframes - # self._segments = LazyGeoFrame( - # Segment, data=lineSegments, store=self) - # self._points = LazyGeoFrame(Spine, data=points, store=self) - - map = MapAnnotations(loader.build(), - lineSegments=lineSegments, - points=points) - - # Save new mmap file in same directory as tif file - import os - pathParse = os.path.splitext(path)[0] # without extension - newMapPath = pathParse + ".mmap" - logger.info("Save new Map from tif file") - map.save(newMapPath) - - self.loadStackWidget(newMapPath) - # map.points[:] - # need to save zarr file first. so that we can create a stack from it within stackwidget - # need to create stackwidget from new map - #only save when user clicks save as def getOpenWidgetDict(self): return self._openWidgetList.getDict() - def loadStackWidget(self, path : str): + def loadStackWidget(self, path : str = None): """Load a stack from a path. Path can be from (.mmap, .tif) @@ -669,8 +525,16 @@ def loadStackWidget(self, path : str): ---------- path : str Full path to (zarr, tif) file + + Returns + ------- + Either a stackWIdget (single timepoint) or a MapWidget (multiple timepoint) """ + if path is None: + logger.warning('TODO: write a file open dialog to open an mmap file') + return + _aWidget = self._openWidgetList.openWidgetFromPath(path) return _aWidget diff --git a/pymapmanager/interface2/runInterfaceBob.py b/pymapmanager/interface2/runInterfaceBob.py index 76ad23ec..335765a5 100644 --- a/pymapmanager/interface2/runInterfaceBob.py +++ b/pymapmanager/interface2/runInterfaceBob.py @@ -35,15 +35,17 @@ def run(): # path = '/Users/cudmore/Desktop/multi_timepoint_map_seg_spine_connected.mmap' + # mw will be map widget if path has multiple timepoints, otherwise mw is a stackwidget2 mw = app.loadStackWidget(path) - centerTimepoint = 2 - plusMinusTimepoint = 1 - spineID = 139 - mw.openStackRun(centerTimepoint, plusMinusTimepoint, spineID=spineID) + # multi timepoint map + # centerTimepoint = 2 + # plusMinusTimepoint = 1 + # spineID = 139 + # mw.openStackRun(centerTimepoint, plusMinusTimepoint, spineID=spineID) # debug tracing plugin - # sw2.runPlugin('Tracing', inDock=True) + # mw.runPlugin('Tracing', inDock=True) sys.exit(app.exec_()) diff --git a/pymapmanager/interface2/stackWidgets/mmWidget2.py b/pymapmanager/interface2/stackWidgets/mmWidget2.py index 09d5b418..0f37ce1d 100644 --- a/pymapmanager/interface2/stackWidgets/mmWidget2.py +++ b/pymapmanager/interface2/stackWidgets/mmWidget2.py @@ -603,8 +603,8 @@ def getUndoRedo(self): logger.error('neither a map or stack widget???') return - logger.info(f' returning undoredo object of type: {type(_undoRedo)}') - print(_undoRedo) + # logger.info(f' returning undoredo object of type: {type(_undoRedo)}') + # print(_undoRedo) return _undoRedo @@ -636,7 +636,7 @@ def _disconnectFromMap(self): except TypeError: pass - def _old_getInitError(self): + def getInitError(self): # TODO: implement this return False