// TODO make this automatically call all panels' method
  private void saveSettings() {
    // save selections as needed
    devices_.saveSettings();
    setupPanelA_.saveSettings();
    if (!ASIdiSPIM.oSPIM) {
      setupPanelB_.saveSettings();
    }
    navigationPanel_.saveSettings();
    acquisitionPanel_.saveSettings();
    settingsPanel_.saveSettings();

    // save tab location in prefs (dialog location now handled by MMDialog)
    prefs_.putInt(MAIN_PREF_NODE, Prefs.Keys.TAB_INDEX, tabbedPane_.getSelectedIndex());
  }
 public void tabsSetEnabled(boolean enabled) {
   tabbedPane_.setEnabled(enabled);
 }
  /**
   * Creates the ASIdiSPIM plugin frame
   *
   * @param gui - Micro-Manager script interface
   * @throws ASIdiSPIMException
   */
  public ASIdiSPIMFrame(ScriptInterface gui) throws ASIdiSPIMException {

    // create interface objects used by panels
    gui_ = gui;
    prefs_ = new Prefs(Preferences.userNodeForPackage(this.getClass()));
    devices_ = new Devices(gui_, prefs_);
    props_ = new Properties(gui_, devices_, prefs_);
    positions_ = new Positions(gui_, devices_);
    joystick_ = new Joystick(devices_, props_);
    cameras_ = new Cameras(gui_, devices_, props_, prefs_);
    controller_ = new ControllerUtils(gui_, props_, prefs_, devices_, positions_);

    // make sure Live mode is turned off (panels assume it can manipulate
    //   cameras which requires live mode to be turned off)
    boolean liveModeOriginally = gui_.isLiveModeOn();
    String cameraOriginal = gui_.getMMCore().getCameraDevice();
    if (liveModeOriginally) {
      gui_.enableLiveMode(false);
    }

    // create the panels themselves
    // in some cases dependencies create required ordering
    devicesPanel_ = new DevicesPanel(gui_, devices_, props_);
    stagePosUpdater_ =
        new StagePositionUpdater(positions_, props_); // needed for setup and navigation

    autofocus_ =
        new AutofocusUtils(
            gui_, devices_, props_, prefs_, cameras_, stagePosUpdater_, positions_, controller_);

    acquisitionPanel_ =
        new AcquisitionPanel(
            gui_,
            devices_,
            props_,
            cameras_,
            prefs_,
            stagePosUpdater_,
            positions_,
            controller_,
            autofocus_);
    setupPanelA_ =
        new SetupPanel(
            gui_,
            devices_,
            props_,
            joystick_,
            Devices.Sides.A,
            positions_,
            cameras_,
            prefs_,
            stagePosUpdater_,
            autofocus_);
    if (!ASIdiSPIM.oSPIM) {
      setupPanelB_ =
          new SetupPanel(
              gui_,
              devices_,
              props_,
              joystick_,
              Devices.Sides.B,
              positions_,
              cameras_,
              prefs_,
              stagePosUpdater_,
              autofocus_);
    } else {
      setupPanelB_ = null;
    }
    navigationPanel_ =
        new NavigationPanel(
            gui_, devices_, props_, joystick_, positions_, prefs_, cameras_, stagePosUpdater_);

    dataAnalysisPanel_ = new DataAnalysisPanel(gui_, prefs_);
    autofocusPanel_ = new AutofocusPanel(gui_, devices_, props_, prefs_, autofocus_);
    settingsPanel_ = new SettingsPanel(gui_, devices_, props_, prefs_, stagePosUpdater_);
    stagePosUpdater_.oneTimeUpdate(); // needed for NavigationPanel
    helpPanel_ = new HelpPanel();
    statusSubPanel_ = new StatusSubPanel(devices_, props_, positions_, stagePosUpdater_);

    // now add tabs to GUI
    // all added tabs must be of type ListeningJPanel
    // only use addLTab, not addTab to guarantee this
    tabbedPane_ = new ListeningJTabbedPane();
    if (isMac()) {
      tabbedPane_.setTabPlacement(JTabbedPane.TOP);
    } else {
      tabbedPane_.setTabPlacement(JTabbedPane.LEFT);
    }
    tabbedPane_.addLTab(navigationPanel_); // tabIndex = 0
    tabbedPane_.addLTab(setupPanelA_); // tabIndex = 1
    if (!ASIdiSPIM.oSPIM) {
      tabbedPane_.addLTab(setupPanelB_); // tabIndex = 2
    }
    tabbedPane_.addLTab(acquisitionPanel_); // tabIndex = 3
    tabbedPane_.addLTab(dataAnalysisPanel_); // tabIndex = 4
    tabbedPane_.addLTab(devicesPanel_); // tabIndex = 5
    final int deviceTabIndex = tabbedPane_.getTabCount() - 1;
    tabbedPane_.addLTab(autofocusPanel_); // tabIndex = 6
    tabbedPane_.addLTab(settingsPanel_); // tabIndex = 7
    tabbedPane_.addLTab(helpPanel_); // tabIndex = 8
    final int helpTabIndex = tabbedPane_.getTabCount() - 1;

    // make taller tabs for easier navigation between them
    // we create own labels instead of having JTabbedPane do it from titles
    final Border paddingBorder = BorderFactory.createEmptyBorder(4, 0, 4, 0);
    for (int i = 0; i < tabbedPane_.getTabCount(); i++) {
      JLabel lab = new JLabel(((ListeningJPanel) tabbedPane_.getComponentAt(i)).getPanelName());
      lab.setBorder(paddingBorder);
      tabbedPane_.setTabComponentAt(i, lab);
    }

    // add the testing panel explicitly by uncommenting following lines
    // intended to only be done in short term for testing
    // TestingPanel testingPanel = new TestingPanel();
    // tabbedPane_.addLTab(testingPanel);

    // attach position updaters
    stagePosUpdater_.addPanel(setupPanelA_);
    if (!ASIdiSPIM.oSPIM) {
      stagePosUpdater_.addPanel(setupPanelB_);
    }
    stagePosUpdater_.addPanel(navigationPanel_);
    stagePosUpdater_.addPanel(statusSubPanel_);

    piezoSleepPreventer_ = new PiezoSleepPreventer(gui_, devices_, props_);

    // attach live mode listeners
    MMStudio.getInstance()
        .getSnapLiveManager()
        .addLiveModeListener((LiveModeListener) setupPanelA_);
    if (!ASIdiSPIM.oSPIM) {
      MMStudio.getInstance()
          .getSnapLiveManager()
          .addLiveModeListener((LiveModeListener) setupPanelB_);
    }
    MMStudio.getInstance()
        .getSnapLiveManager()
        .addLiveModeListener((LiveModeListener) navigationPanel_);
    MMStudio.getInstance()
        .getSnapLiveManager()
        .addLiveModeListener(
            new LiveModeListener() {
              // make sure to "wake up" any piezos with autosleep enabled before we start imaging
              @Override
              public void liveModeEnabled(boolean enabled) {
                if (enabled) {
                  piezoSleepPreventer_.start();
                } else {
                  piezoSleepPreventer_.stop();
                }
              }
            });

    // set scan for live mode to be triangle (now live mode setting not affected by SPIM setting)
    props_.setPropValue(
        new Devices.Keys[] {Devices.Keys.GALVOA, Devices.Keys.GALVOB},
        Properties.Keys.SA_PATTERN_X,
        Properties.Values.SAM_TRIANGLE,
        true);

    // make sure gotDeSelected() and gotSelected() get called whenever we switch tabs
    tabbedPane_.addChangeListener(
        new ChangeListener() {
          int lastSelectedIndex_ = tabbedPane_.getSelectedIndex();

          @Override
          public void stateChanged(ChangeEvent e) {
            ((ListeningJPanel) tabbedPane_.getComponentAt(lastSelectedIndex_)).gotDeSelected();
            ((ListeningJPanel) tabbedPane_.getSelectedComponent()).gotSelected();
            lastSelectedIndex_ = tabbedPane_.getSelectedIndex();
          }
        });

    // put frame back where it was last time
    this.loadAndRestorePosition(100, 100);

    // clear any previous joystick settings
    joystick_.unsetAllJoysticks();

    // gotSelected will be called because we put this after adding the ChangeListener
    tabbedPane_.setSelectedIndex(
        helpTabIndex); // setSelectedIndex(0) just after initialization doesn't fire ChangeListener,
                       // so switch to help panel first
    tabbedPane_.setSelectedIndex(
        prefs_.getInt(
            MAIN_PREF_NODE,
            Prefs.Keys.TAB_INDEX,
            deviceTabIndex)); // default to devicesPanel_ on first run

    // set up the window
    add(tabbedPane_); // add the pane to the GUI window
    setTitle(ASIdiSPIM.menuName + " Control");
    pack(); // shrinks the window as much as it can
    setResizable(false);

    // take care of shutdown tasks when window is closed
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    // add status panel as an overlay that is visible from all tabs
    Container glassPane = (Container) getGlassPane();
    glassPane.setVisible(true);
    glassPane.setLayout(
        new MigLayout("", "[" + this.getWidth() + "]", "[" + this.getHeight() + "]"));
    glassPane.add(statusSubPanel_, "dock south");

    // restore live mode and camera
    if (liveModeOriginally) {
      gui_.enableLiveMode(true);
    }
    try {
      gui_.getMMCore().setCameraDevice(cameraOriginal);
    } catch (Exception ex) {
      // do nothing
    }
  }