          if retval:
              logger.debug("Sending should stop")
          return retval
  
      def request_refresh(self) -> None:
          """ Handle a GUI trigger or a training thread trigger (after a mask toggle) request to set
          the refresh trigger to ``True`` to request a refresh on the next pass of the
          training loop. """
          with self._lock:
              self._triggers["refresh"] = True
  
      def request_mask_toggle(self) -> None:
          """ Handle a GUI trigger request to set the mask toggle to ``True`` to
          request a mask toggle on next pass of the training loop. """
          logger.verbose("Toggle mask display requested...")  # type:ignore
          with self._lock:
              self._triggers["toggle_mask"] = True
  
      def add_image(self, name: str, image: np.ndarray) -> None:
          """ Add a preview image to the preview buffer.
  
          Parameters
          ----------
          name: str
              The name of the preview image to add to the buffer
          image: :class:`numpy.ndarray`
              The preview image to add to the buffer in BGR format.
          """
          with self._lock:
              logger.debug("Adding image '%s' of shape %s to preview buffer", name, image.shape)
              self._preview_buffer[name] = image[..., 2::-1]  # Switch to RGB
              self._needs_update = True
  
      def display_preview(self) -> None:
          """ Display an image preview in a resizable window. """
          if self._needs_update:
              logger.debug("Updating preview")
              with self._lock:
                  for name, image in self._preview_buffer.items():
                      if (name not in self._images or  # new preview or preview was closed
                              not plt.fignum_exists(self._images[name][0].number)):
                          self._create_resizable_window(name, image.shape)
                          if self._triggers["full_size"]:  # Can only be true if preview was closed
                              self._set_resize_callback()
                      plt.figure(name)
                      plt.imshow(image)
                  self._needs_update = False
              plt.show(block=False)
              logger.debug("preview updated")  # type: ignore
          plt.pause(0.1)
  
      def _create_resizable_window(self, name: str, image_shape: tuple) -> None:
          """ Create a resizable Matplotlib window to hold the preview image.
  
          Parameters
          ----------
          name: str
              The name to display in the window header and for window identification
 
</s> remove         Parameters
        ----------
        name: str
            The name to display in the window header and for window identification
        shape: tuple
            The (`rows`, `columns`, `channels`) of the image to be displayed
 </s> add         Returns
        -------
        :class:`lib.multithreading.FSThread` or ``None``
            The thread that holds the preview viewer if preview is selected otherwise ``None`` </s> remove 
        logger.debug("Preview window keypress '%s' received", key)
        if key == "r":
            print("\n")  # Let log print on different line from loss output
            logger.info("Refresh preview requested...")

        with self._lock:
            if key == "f":
                self._toggle_size()
            else:
                self._triggers[self._callbacks[key]] = True

    def _on_resize(self,
                   event: backend_bases.ResizeEvent) -> None:  # noqa # pylint:disable=unused-argument
        """ If the display is set to `actual size` then the image needs to be resized on any window
        resize event. """
        for fig, size in self._images.values():
            fig.set_size_inches(size)

    def _on_close(self,
                   event: backend_bases.CloseEvent) -> None:  # noqa # pylint:disable=unused-argument
        """ Force an update when the figure has been closed to relaunch it. """
        logger.debug("Preview close detected")
        with self._lock:
            self._needs_update = True
 </s> add         logger.debug("Sending shutdown to preview viewer")
        self._triggers["shutdown"].set() </s> remove         """ Check whether the mask should be toggled and return the value. If ``True`` is returned
        then resets mask toggle back to ``False``

        Returns
        -------
        bool
            ``True`` if the mask should be toggled otherwise ``False``. """
        with self._lock:
            retval = self._triggers["toggle_mask"]
            if retval:
                logger.debug("Sending toggle mask")
                self._triggers["toggle_mask"] = False
 </s> add         """ bool: Check whether the mask should be toggled and return the value. If ``True`` is
        returned then resets mask toggle back to ``False`` """
        if not self._active:
            return False
        retval = self._triggers["toggle_mask"].is_set()
        if retval:
            logger.debug("Sending toggle mask")
            self._triggers["toggle_mask"].clear() </s> remove         """ Check whether the preview should be updated and return the value. If ``True`` is
        returned then resets the refresh trigger back to ``False``

        Returns
        -------
        bool
            ``True`` if the preview should be refreshed otherwise ``False``. """
        with self._lock:
            retval = self._triggers["refresh"]
            if retval:
                logger.debug("Sending should refresh")
                self._triggers["refresh"] = False
            return retval
 </s> add         """ bool: Check whether the preview should be updated and return the value. If ``True`` is
        returned then resets the refresh trigger back to ``False`` """
        if not self._active:
            return False
        retval = self._triggers["refresh"].is_set()
        if retval:
            logger.debug("Sending should refresh")
            self._triggers["refresh"].clear()
        return retval </s> remove         logger.debug("Creating figure '%s' for image shape %s", name, image_shape)
        if not self._dpi:
            self._dpi = get_dpi()
        height, width = image_shape[:2]
        size = width / self._dpi, height / self._dpi
        fig = plt.figure(name, figsize=size)
        axes = plt.Axes(fig, [0., 0., 1., 1.])  # Remove axes and whitespace
        axes.set_axis_off()
        fig.add_axes(axes)
        fig.canvas.mpl_connect("key_press_event", self._on_key_press)
        fig.canvas.mpl_connect("close_event", self._on_close)
        logger.debug("Created display figure of size: %s", size)
        self._images[name] = (fig, size)

    def _set_resize_callback(self):
        """ Sets the resize callback if displaying preview at actual size or removes it if
        displaying at screen-fit size. """
        if self._triggers["full_size"]:
            logger.debug("Setting resize callback for actual size display")
            for fig, size in self._images.values():
                self._resize_ids.append((fig, fig.canvas.mpl_connect("resize_event",
                                                                     self._on_resize)))
                fig.set_size_inches(size)
        else:
            logger.debug("Removing resize callback for screen-fit display")
            for fig, cid in self._resize_ids:
                fig.canvas.mpl_disconnect(cid)
            self._resize_ids = []

    def _on_key_press(self, event: backend_bases.KeyEvent) -> None:
        """ Callbacks for keypresses to update the requested trigger.

        - `F` (toggle full-size/fit to window)
        - `M` (toggle mask),
        - `R` (refresh preview),
        - `S` (save now)
        - `Enter` (save and exit)
 </s> add         if not self._active:
            return None
        thread = FSThread(target=Preview,
                          name="preview",
                          args=(self._buffer, ),
                          kwargs=dict(triggers=self._triggers))
        thread.start()
        return thread
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
          if retval:
              logger.debug("Sending should stop")
          return retval
  
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
    def _launch_thread(self) -> Optional[FSThread]:
        """ Launch the preview viewer in it's own thread if preview has been selected
  
          Parameters
          ----------
          name: str
              The name to display in the window header and for window identification
keep keep keep keep replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace keep keep keep keep keep
 Training - Use custom preview pop-out 
scripts/train.py