
/*LICENSE_START*/
/*
 *  Copyright (C) 2025 Washington University School of Medicine
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
/*LICENSE_END*/

#define __VOLUME_MONTAGE_SETUP_DIALOG_DECLARE__
#include "VolumeMontageSetupDialog.h"
#undef __VOLUME_MONTAGE_SETUP_DIALOG_DECLARE__

#include <cmath>

#include <QCheckBox>
#include <QComboBox>
#include <QDoubleSpinBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QQuaternion>
#include <QSpinBox>
#include <QStackedLayout>
#include <QVBoxLayout>

#include "Brain.h"
#include "BrowserTabContent.h"
#include "CaretAssert.h"
#include "CaretDataFileSelectionModel.h"
#include "CaretDataFileSelectionComboBox.h"
#include "EnumComboBoxTemplate.h"
#include "EventManager.h"
#include "EventGraphicsPaintSoonAllWindows.h"
#include "EventUserInterfaceUpdate.h"
#include "GuiManager.h"
#include "HistologySlice.h"
#include "HistologySlicesFile.h"
#include "Matrix4x4.h"
#include "MetaVolumeFile.h"
#include "ModelVolume.h"
#include "OverlaySet.h"
#include "VolumeFile.h"
#include "VolumeSliceViewPlaneEnum.h"
#include "WuQtUtilities.h"

using namespace caret;


    
/**
 * \class caret::VolumeMontageSetupDialog 
 * \brief Dialog for setting up volume montages
 * \ingroup GuiQt
 */

/**
 * Constructor.
 * @param browserWindowIndex
 *    Index of browser window
 * @param browserTabContent
 *    Content of browser tab content
 * @param underlayVolumeFile
 *    The underlay volume file
 * @param underlaySliceViewPlane
 *    The slice view plane
 * @param parent
 *    The parent widget
 */
VolumeMontageSetupDialog::VolumeMontageSetupDialog(const int32_t browserWindowIndex,
                                                   BrowserTabContent* browserTabContent,
                                                   VolumeFile* underlayVolumeFile,
                                                   const VolumeSliceViewPlaneEnum::Enum underlaySliceViewPlane,
                                                   QWidget* parent)
: WuQDialogModal("Setup Volume Montage",
                 parent),
m_browserWindowIndex(browserWindowIndex),
m_browserTabContent(browserTabContent),
m_underlayVolumeFile(underlayVolumeFile),
m_underlaySliceViewPlane(underlaySliceViewPlane)
{
    CaretAssert(m_browserTabContent);
    CaretAssert(m_underlayVolumeFile);
    CaretAssert(m_underlaySliceViewPlane != VolumeSliceViewPlaneEnum::ALL);
    
    m_dialogCreationInProgressFlag = true;

    /*
     * Get Montage Info
     */
    const int32_t numRows(browserTabContent->getVolumeMontageNumberOfRows());
    const int32_t numCols(browserTabContent->getVolumeMontageNumberOfColumns());
    if (m_underlaySliceViewPlane == VolumeSliceViewPlaneEnum::ALL) {
        m_underlaySliceViewPlane = VolumeSliceViewPlaneEnum::AXIAL;
    }

    /*
     * Get histology slices files and volume files
     */
    Brain* brain(GuiManager::get()->getBrain());
    CaretAssert(brain);
    const int32_t numHistologySlicesFiles(brain->getNumberOfHistologySlicesFiles());
    
    /*
     * Set montage extent using Histology Slices File or Volume File
     */
    QLabel* montageExtentFileTypeLabel(new QLabel("Set Using: "));
    m_montageExtentFileTypeComboBox = new QComboBox();
    QObject::connect(m_montageExtentFileTypeComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
                     this, &VolumeMontageSetupDialog::montageExtentFileTypeComboBoxActivated);
    if (numHistologySlicesFiles > 0) {
        m_montageExtentTypeHistologyFileIndex = m_montageExtentFileTypeComboBox->count();
        m_montageExtentFileTypeComboBox->addItem("Histology Slices File");
    }
    else {
        m_montageExtentTypeHistologyFileIndex = -1;
    }
    m_montageExtentTypeVolumeFileIndex = m_montageExtentFileTypeComboBox->count();
    m_montageExtentFileTypeComboBox->addItem("Volume File");

    /*
     * Montage Underlay Volume File
     */
    QLabel* volumeFileLabel(new QLabel("Underlay Volume File:"));
    QLabel* underlayVolumeFileNameLabel(new QLabel(""));
    underlayVolumeFileNameLabel->setText(m_underlayVolumeFile->getFileNameNoPath());
    
    /*
     * Montage Rows/Columns
     */
    const int32_t maxVal(100);
    const int32_t maxWidth(160);
    QLabel* rowsLabel(new QLabel("Montage Rows:"));
    m_montageInputRowsSpinBox = new QSpinBox();
    m_montageInputRowsSpinBox->setRange(1, maxVal);
    m_montageInputRowsSpinBox->setMaximumWidth(maxWidth);
    QObject::connect(m_montageInputRowsSpinBox,  static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
                     this, &VolumeMontageSetupDialog::montageInputRowsValueChanged);
    
    QLabel* columnsLabel(new QLabel(" Columns:"));
    m_montageInputColumnsSpinBox = new QSpinBox();
    m_montageInputColumnsSpinBox->setRange(1, maxVal);
    m_montageInputColumnsSpinBox->setMaximumWidth(maxWidth);
    QObject::connect(m_montageInputColumnsSpinBox,  static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
                     this, &VolumeMontageSetupDialog::montageInputColumnsValueChanged);
    
    QLabel* numberOfSlicesLabel(new QLabel(" Slices:"));
    m_montageInputNumberOfSlicesLabel = new QLabel();

    QLabel* slicePlaneLabel(new QLabel("Slice Plane: "));
    QLabel* montageSlicePlaneLabel(new QLabel(VolumeSliceViewPlaneEnum::toGuiName(m_underlaySliceViewPlane)));
    QHBoxLayout* slicePlaneLayout(new QHBoxLayout());
    slicePlaneLayout->addWidget(slicePlaneLabel);
    slicePlaneLayout->addWidget(montageSlicePlaneLabel);
    slicePlaneLayout->addStretch();
    
    QHBoxLayout* setExtentLayout(new QHBoxLayout());
    setExtentLayout->addWidget(montageExtentFileTypeLabel);
    setExtentLayout->addWidget(m_montageExtentFileTypeComboBox);
    setExtentLayout->addStretch();

    QHBoxLayout* underlayVolumeLayout(new QHBoxLayout());
    underlayVolumeLayout->addWidget(volumeFileLabel);
    underlayVolumeLayout->addWidget(underlayVolumeFileNameLabel);
    underlayVolumeLayout->addStretch();

    QHBoxLayout* montageSizeLayout(new QHBoxLayout());
    montageSizeLayout->addWidget(rowsLabel);
    montageSizeLayout->addWidget(m_montageInputRowsSpinBox);
    montageSizeLayout->addWidget(columnsLabel);
    montageSizeLayout->addWidget(m_montageInputColumnsSpinBox);
    montageSizeLayout->addWidget(numberOfSlicesLabel);
    montageSizeLayout->addWidget(m_montageInputNumberOfSlicesLabel);
    montageSizeLayout->addStretch();
    
    QGroupBox* montageGroupBox(new QGroupBox("Montage"));
    montageGroupBox->setAlignment(Qt::AlignHCenter);
    QVBoxLayout* montageLayout(new QVBoxLayout(montageGroupBox));
    montageLayout->addLayout(underlayVolumeLayout);
    montageLayout->addLayout(montageSizeLayout);
    montageLayout->addLayout(slicePlaneLayout);
    
    m_montageExtentVolumeFileWidget    = createVolumeSliceInputWidget();
    m_montageExtentHistologyFileWidget = createHistologyWidget();

    m_volumeSliceRangeSourceLayout = new QStackedLayout();
    m_volumeSliceRangeSourceLayout->addWidget(m_montageExtentHistologyFileWidget);
    m_volumeSliceRangeSourceLayout->addWidget(m_montageExtentVolumeFileWidget);

    QGroupBox* montageExtentWidget(new QGroupBox("Montage Extent"));
    montageExtentWidget->setAlignment(Qt::AlignHCenter);
    QVBoxLayout* montageExtentLayout(new QVBoxLayout(montageExtentWidget));
    montageExtentLayout->setContentsMargins(0, 0, 0, 0);
    montageExtentLayout->addLayout(setExtentLayout);
    montageExtentLayout->addSpacing(8);
    montageExtentLayout->addLayout(m_volumeSliceRangeSourceLayout);


    QWidget* widget(new QWidget());
    QVBoxLayout* layout(new QVBoxLayout(widget));
    layout->addWidget(montageGroupBox);
    layout->addSpacing(8);
    layout->addWidget(montageExtentWidget);
    layout->addSpacing(8);
    layout->addWidget(createMontageOutputWidget());
    
    setCentralWidget(widget,
                     ScrollAreaStatus::SCROLL_AREA_NEVER);
    
    /*
     * Loads data and sets up dialog
     */
    histologyFileSelected(m_histologyFileSelectionComboBox->getSelectedFile());
    volumeFileSelected(m_volumeFileSelectionComboBox->getSelectedFile());
    QSignalBlocker rowsBlocker(m_montageInputRowsSpinBox);
    m_montageInputRowsSpinBox->setValue(numRows);
    QSignalBlocker columnsBlocker(m_montageInputColumnsSpinBox);
    m_montageInputColumnsSpinBox->setValue(numCols);
    m_dialogCreationInProgressFlag = false;
    montageInputRowOrColumnValueChanged();
    
        m_applyPushButton = addUserPushButton("Apply",
                                          QDialogButtonBox::ButtonRole::AcceptRole);
    
    montageExtentFileTypeComboBoxActivated(m_montageExtentFileTypeComboBox->currentIndex());
    updateMontageOutputWidget();
}

/**
 * Destructor.
 */
VolumeMontageSetupDialog::~VolumeMontageSetupDialog()
{

}

/**
 * @return New instance of volume slice input widget
 */
QWidget*
VolumeMontageSetupDialog::createVolumeSliceInputWidget()
{
    QLabel* volumeFileLabel(new QLabel("Volume File:"));
    std::vector<DataFileTypeEnum::Enum> volumeFileTypes { DataFileTypeEnum::VOLUME, DataFileTypeEnum::META_VOLUME };
    std::pair<CaretDataFileSelectionModel*, CaretDataFileSelectionComboBox*> volumeModelAndFileCombo
    = CaretDataFileSelectionComboBox::newInstanceForFileType(DataFileTypeEnum::VOLUME, this);
    m_volumeFileSelectionComboBox = volumeModelAndFileCombo.second;
    QObject::connect(m_volumeFileSelectionComboBox, &CaretDataFileSelectionComboBox::fileSelected,
                     this, &VolumeMontageSetupDialog::volumeFileSelected);
    volumeModelAndFileCombo.first->setSelectedFile(m_underlayVolumeFile);

    QLabel* startLabel(new QLabel("Start:"));
    QLabel* endLabel(new QLabel("End:"));
    QLabel* sliceLabel(new QLabel("Slice"));
    QLabel* sliceIndexLabel(new QLabel("Slice Index"));
    QLabel* coordinateLabel(new QLabel("Slice Coordinate"));
    
    m_volumeStartSliceIndexSpinBox = new QSpinBox();
    m_volumeStartSliceIndexSpinBox->setMinimumWidth(s_minimumSpinBoxWidth);
    QObject::connect(m_volumeStartSliceIndexSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
                     this, &VolumeMontageSetupDialog::volumeStartSliceIndexSpinBoxValueChanged);
    
    m_volumeEndSliceIndexSpinBox = new QSpinBox();
    m_volumeEndSliceIndexSpinBox->setMinimumWidth(s_minimumSpinBoxWidth);
    QObject::connect(m_volumeEndSliceIndexSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
                     this, &VolumeMontageSetupDialog::volumeEndSliceIndexSpinBoxValueChanged);
    
    m_volumeStartSliceCoordinateLabel = new QLabel();
    m_volumeEndSliceCoordinateLabel   = new QLabel();
    
    const int32_t COL_LABEL(0);
    const int32_t COL_INDEX(1);
    const int32_t COL_COORD(2);
    const int32_t STRETCH_YES(100);
    
    QHBoxLayout* volumeFileLayout(new QHBoxLayout());
    volumeFileLayout->addWidget(volumeFileLabel);
    volumeFileLayout->addWidget(m_volumeFileSelectionComboBox->getWidget());
    volumeFileLayout->addStretch();

    QGridLayout* sliceCoordLayout(new QGridLayout());
    int row = sliceCoordLayout->rowCount();
    sliceCoordLayout->setColumnStretch(3, STRETCH_YES);
    sliceCoordLayout->setRowStretch(100, 100);
    sliceCoordLayout->addWidget(sliceLabel,
                                row, COL_LABEL, Qt::AlignHCenter);
    sliceCoordLayout->addWidget(sliceIndexLabel,
                                row, COL_INDEX, Qt::AlignHCenter);
    sliceCoordLayout->addWidget(coordinateLabel,
                                row, COL_COORD, Qt::AlignHCenter);
    ++row;
    sliceCoordLayout->addWidget(endLabel,
                                row, COL_LABEL);
    sliceCoordLayout->addWidget(m_volumeEndSliceIndexSpinBox,
                                row, COL_INDEX);
    sliceCoordLayout->addWidget(m_volumeEndSliceCoordinateLabel,
                                row, COL_COORD);
    ++row;
    sliceCoordLayout->addWidget(startLabel,
                                row, COL_LABEL);
    sliceCoordLayout->addWidget(m_volumeStartSliceIndexSpinBox,
                                row, COL_INDEX);
    sliceCoordLayout->addWidget(m_volumeStartSliceCoordinateLabel,
                                row, COL_COORD);
    ++row;

    QWidget* widget(new QWidget());
    QVBoxLayout* layout(new QVBoxLayout(widget));
    layout->addLayout(volumeFileLayout);
    layout->addLayout(sliceCoordLayout);
    layout->addStretch();

    return widget;
}

/**
 * @return New instance of the histology section
 */
QWidget*
VolumeMontageSetupDialog::createHistologyWidget()
{
    QLabel* histologyFileLabel(new QLabel("Histology Slices File:"));
    std::pair<CaretDataFileSelectionModel*, CaretDataFileSelectionComboBox*> histModelAndFileCombo
    = CaretDataFileSelectionComboBox::newInstanceForFileType(DataFileTypeEnum::HISTOLOGY_SLICES, this);
    m_histologyFileSelectionComboBox = histModelAndFileCombo.second;
    QObject::connect(m_histologyFileSelectionComboBox, &CaretDataFileSelectionComboBox::fileSelected,
                     this, &VolumeMontageSetupDialog::histologyFileSelected);
    
    m_histologyAlignToFileAxisCheckBox = new QCheckBox("Align to Histology File's Axis");
    m_histologyAlignToFileAxisCheckBox->setChecked(true);
    QObject::connect(m_histologyAlignToFileAxisCheckBox, &QCheckBox::clicked,
                     this, &VolumeMontageSetupDialog::histologyAlignToHistologyFileAxisCheckBoxClicked);
    
    QLabel* startLabel(new QLabel("Start:"));
    QLabel* endLabel(new QLabel("End:"));
    QLabel* sliceLabel(new QLabel("Slice"));
    QLabel* sliceNumberLabel(new QLabel("Slice Number"));
    QLabel* coordinateLabel(new QLabel("Coordinate"));
    QLabel* sliceNameLabel(new QLabel("Slice Name"));

    m_histologyStartSliceNumberSpinBox = new QSpinBox();
    m_histologyStartSliceNumberSpinBox->setMinimumWidth(s_minimumSpinBoxWidth);
    QObject::connect(m_histologyStartSliceNumberSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
                     this, &VolumeMontageSetupDialog::histologyStartSliceNumberSpinBoxValueChanged);

    m_histologyEndSliceNumberSpinBox = new QSpinBox();
    m_histologyEndSliceNumberSpinBox->setMinimumWidth(s_minimumSpinBoxWidth);
    QObject::connect(m_histologyEndSliceNumberSpinBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
                     this, &VolumeMontageSetupDialog::histologyEndSliceNumberSpinBoxValueChanged);

    m_histologyStartSliceNameComboBox = new QComboBox();
    m_histologyStartSliceNameComboBox->setMinimumWidth(s_minimumSpinBoxWidth);
    QObject::connect(m_histologyStartSliceNameComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
                     this, &VolumeMontageSetupDialog::histologyStartSliceNameComboBoxActivated);

    m_histologyEndSliceNameComboBox = new QComboBox();
    m_histologyEndSliceNameComboBox->setMinimumWidth(s_minimumSpinBoxWidth);
    QObject::connect(m_histologyEndSliceNameComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
                     this, &VolumeMontageSetupDialog::histologyEndSliceNameComboBoxActivated);

    m_histologyStartSliceCoordinateLabel = new QLabel();
    m_histologyEndSliceCoordinateLabel   = new QLabel();
    
    const int32_t COL_LABEL(0);
    const int32_t COL_NUMBER(1);
    const int32_t COL_NAME(2);
    const int32_t COL_COORD(3);
    
    QGridLayout* fileAxisLayout(new QGridLayout());
    fileAxisLayout->setContentsMargins(0, 0, 0, 0);
    fileAxisLayout->setColumnStretch(1, 100);
    fileAxisLayout->addWidget(histologyFileLabel,
                              0, 0);
    fileAxisLayout->addWidget(m_histologyFileSelectionComboBox->getWidget(),
                              0, 1);
    fileAxisLayout->addWidget(m_histologyAlignToFileAxisCheckBox,
                              1, 0, 1, 2, Qt::AlignLeft);
    
    QWidget* widget(new QWidget());
    QGridLayout* layout(new QGridLayout(widget));
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setColumnStretch(4, 100);
    int row(layout->rowCount());
    layout->addLayout(fileAxisLayout,
                      row, COL_LABEL, 1, 5);
    ++row;
    layout->addWidget(sliceLabel,
                      row, COL_LABEL);
    layout->addWidget(sliceNumberLabel,
                      row, COL_NUMBER, Qt::AlignHCenter);
    layout->addWidget(sliceNameLabel,
                      row, COL_NAME, Qt::AlignHCenter);
    layout->addWidget(coordinateLabel,
                      row, COL_COORD, Qt::AlignHCenter);
    ++row;
    layout->addWidget(endLabel,
                      row, COL_LABEL);
    layout->addWidget(m_histologyEndSliceNumberSpinBox,
                      row, COL_NUMBER);
    layout->addWidget(m_histologyEndSliceNameComboBox,
                      row, COL_NAME);
    layout->addWidget(m_histologyEndSliceCoordinateLabel,
                      row, COL_COORD);
    ++row;
    layout->addWidget(startLabel,
                      row, COL_LABEL);
    layout->addWidget(m_histologyStartSliceNumberSpinBox,
                      row, COL_NUMBER);
    layout->addWidget(m_histologyStartSliceNameComboBox,
                      row, COL_NAME);
    layout->addWidget(m_histologyStartSliceCoordinateLabel,
                      row, COL_COORD);
    ++row;

    return widget;
}

/**
 * @return New instance of the montage section
 */
QWidget*
VolumeMontageSetupDialog::createMontageOutputWidget()
{
    QLabel* parasagittalLabel = new QLabel("Parasagittal:");
    QLabel* coronalLabel      = new QLabel("Coronal:");
    QLabel* axialLabel        = new QLabel("Axial:");
    QLabel* sliceAxisLabel    = new QLabel("Slice Axis");
    QLabel* sliceIndexLabel(new QLabel("Index"));
    QLabel* coordinateLabel(new QLabel("Coordinate"));

    m_montageOutputParagittalSliceIndexSpinBox = new QDoubleSpinBox();
    
    m_montageOutputCoronalSliceIndexSpinBox = new QDoubleSpinBox();
    
    m_montageOutputAxialSliceIndexSpinBox = new QDoubleSpinBox();
    
    m_montageOutputParagittalSliceCoordinateSpinBox = new QDoubleSpinBox();
    
    m_montageOutputCoronalSliceCoordinateSpinBox = new QDoubleSpinBox();
    
    m_montageOutputAxialSliceCoordinateSpinBox = new QDoubleSpinBox();

    const int32_t COL_LABEL(0);
    const int32_t COL_INDEX(1);
    const int32_t COL_COORD(2);
    const int32_t COL_STRETCH(3);
    const int32_t STRETCH_YES(100);
    QGridLayout* pcaLayout(new QGridLayout());
    pcaLayout->setColumnStretch(COL_STRETCH,
                                STRETCH_YES);
    int32_t row(pcaLayout->rowCount());
    pcaLayout->addWidget(sliceAxisLabel,
                         row, COL_LABEL);
    pcaLayout->addWidget(sliceIndexLabel,
                         row, COL_INDEX);
    pcaLayout->addWidget(coordinateLabel,
                         row, COL_COORD);
    ++row;
    pcaLayout->addWidget(parasagittalLabel,
                         row, COL_LABEL);
    pcaLayout->addWidget(m_montageOutputParagittalSliceIndexSpinBox,
                         row, COL_INDEX);
    pcaLayout->addWidget(m_montageOutputParagittalSliceCoordinateSpinBox,
                         row, COL_COORD);
    ++row;
    pcaLayout->addWidget(coronalLabel,
                         row, COL_LABEL);
    pcaLayout->addWidget(m_montageOutputCoronalSliceIndexSpinBox,
                         row, COL_INDEX);
    pcaLayout->addWidget(m_montageOutputCoronalSliceCoordinateSpinBox,
                         row, COL_COORD);
    ++row;
    pcaLayout->addWidget(axialLabel,
                         row, COL_LABEL);
    pcaLayout->addWidget(m_montageOutputAxialSliceIndexSpinBox,
                         row, COL_INDEX);
    pcaLayout->addWidget(m_montageOutputAxialSliceCoordinateSpinBox,
                         row, COL_COORD);
    ++row;

    QLabel* rangeLabel(new QLabel("Montage Range (start to end):"));
    m_montageOutputRangeLabel = new QLabel();
    m_montageOutputRangeLabel->setToolTip("Disance between start and end volume slices");
    
    QLabel* stepLabel(new QLabel("Montage Step:"));
    m_montageOutputSliceStepLabel = new QLabel();
    m_montageOutputSliceStepLabel->setToolTip("Step value in Toolbar->Montage");

    QLabel* stepDistanceLabel(new QLabel("Montage Step Distance:"));
    m_montageOutputStepDistanceLabel = new QLabel();
    m_montageOutputStepDistanceLabel->setToolTip("Distance between consecutive montage slices");
    
    QLabel* rotationAnglesLabel(new QLabel("MPR Rotation Angles:"));
    m_montageOutputRotationAnglesLabel = new QLabel();
    
    QLabel* sliceViewPlaneLabel(new QLabel("Slice Plane:"));
    m_montageOutputSliceViewPlaneLabel = new QLabel();
    
    QGridLayout* stepLayout(new QGridLayout());
    stepLayout->setColumnStretch(2, STRETCH_YES);
    int32_t stepLayoutRow(stepLayout->rowCount());
    stepLayout->addWidget(rangeLabel,
                          stepLayoutRow, 0);
    stepLayout->addWidget(m_montageOutputRangeLabel,
                          stepLayoutRow, 1);
    ++stepLayoutRow;
    stepLayout->addWidget(stepDistanceLabel,
                          stepLayoutRow, 0);
    stepLayout->addWidget(m_montageOutputStepDistanceLabel,
                          stepLayoutRow, 1);
    ++stepLayoutRow;
    stepLayout->addWidget(stepLabel,
                          stepLayoutRow, 0);
    stepLayout->addWidget(m_montageOutputSliceStepLabel,
                          stepLayoutRow, 1);
    ++stepLayoutRow;
    stepLayout->addWidget(sliceViewPlaneLabel,
                          stepLayoutRow, 0);
    stepLayout->addWidget(m_montageOutputSliceViewPlaneLabel,
                          stepLayoutRow, 1);
    ++stepLayoutRow;
    stepLayout->addWidget(rotationAnglesLabel,
                          stepLayoutRow, 0);
    stepLayout->addWidget(m_montageOutputRotationAnglesLabel,
                          stepLayoutRow, 1);
    ++stepLayoutRow;
    
    QGroupBox* widget(new QGroupBox("Montage Output"));
    widget->setAlignment(Qt::AlignHCenter);
    QHBoxLayout* layout(new QHBoxLayout(widget));
    layout->addLayout(pcaLayout);
    layout->addSpacing(10);
    layout->addWidget(WuQtUtilities::createVerticalLineWidget());
    layout->addSpacing(10);
    layout->addLayout(stepLayout);
    layout->addStretch();
    
    return widget;
}

/**
 * Called when montage rows value changed
 * @param value
 *    New value
 */
void
VolumeMontageSetupDialog::montageInputRowsValueChanged(int /*value*/)
{
    montageInputRowOrColumnValueChanged();
}

/**
 * Called when montage columns value changed
 * @param value
 *    New value
 */
void
VolumeMontageSetupDialog::montageInputColumnsValueChanged(int /*value*/)
{
    montageInputRowOrColumnValueChanged();
}

/**
 * Called when a montage row or column value changed
 */
void
VolumeMontageSetupDialog::montageInputRowOrColumnValueChanged()
{
    const int32_t numRows(m_montageInputRowsSpinBox->value());
    const int32_t numCols(m_montageInputColumnsSpinBox->value());
    const int32_t numberOfSlices(numCols * numRows);
    m_montageInputNumberOfSlicesLabel->setText(AString::number(numberOfSlices));

    updateMontageOutputWidget();
}

/**
 * Called when histology file changed
 * @param caretDataFile
 *    File selected by user
 */
void
VolumeMontageSetupDialog::histologyFileSelected(CaretDataFile* caretDataFile)
{
    m_histologyStartSliceNameComboBox->clear();
    m_histologyEndSliceNameComboBox->clear();
    bool validFlag(false);
    if (caretDataFile != NULL) {
        HistologySlicesFile* hsf(caretDataFile->castToHistologySlicesFile());
        if (hsf != NULL) {
            const int32_t lastSliceIndex(hsf->getNumberOfHistologySlices());
            if (lastSliceIndex >= 0) {
                /*
                 * Load slice name combo boxes
                 */
                for (int32_t i = 0; i < lastSliceIndex; i++) {
                    m_histologyStartSliceNameComboBox->addItem(hsf->getHistologySliceByIndex(i)->getSliceName());
                    m_histologyEndSliceNameComboBox->addItem(hsf->getHistologySliceByIndex(i)->getSliceName());
                }

                /*
                 * Load slice number spin boxes
                 */
                QSignalBlocker startBlocker(m_histologyStartSliceNumberSpinBox);
                m_histologyStartSliceNumberSpinBox->setRange(1, lastSliceIndex);
                m_histologyStartSliceNumberSpinBox->setValue(1);
                histologyStartSliceNumberSpinBoxValueChanged(m_histologyStartSliceNumberSpinBox->value());
                QSignalBlocker endBlocker(m_histologyEndSliceNumberSpinBox);
                m_histologyEndSliceNumberSpinBox->setRange(1, lastSliceIndex);
                m_histologyEndSliceNumberSpinBox->setValue(lastSliceIndex);
                histologyEndSliceNumberSpinBoxValueChanged(m_histologyEndSliceNumberSpinBox->value());
                
                validFlag = true;
            }
        }
    }
    m_histologyStartSliceNumberSpinBox->setEnabled(validFlag);
    m_histologyEndSliceNumberSpinBox->setEnabled(validFlag);
    
    updateMontageOutputWidget();
}

/**
 * Called when value changed
 * @param sliceNumber
 *    New value
 */
void
VolumeMontageSetupDialog::histologyStartSliceNumberSpinBoxValueChanged(int sliceNumber)
{
    FunctionResultValue<Vector3D> result(histologySliceNumberToCoordinate(sliceNumber));
    if (result.isOk()) {
        m_histologyStartSliceCoordinateLabel->setText(result.getValue().toString());
    }
    else {
        m_histologyStartSliceCoordinateLabel->setText("Invalid");
    }
    
    m_histologyStartSliceNumberSpinBox->setValue(sliceNumber);
    m_histologyStartSliceNameComboBox->setCurrentIndex(sliceNumber - 1);
    
    updateMontageOutputWidget();
}

/**
 * Called when value changed
 * @param sliceNumber
 *    New value
 */
void
VolumeMontageSetupDialog::histologyEndSliceNumberSpinBoxValueChanged(int sliceNumber)
{
    FunctionResultValue<Vector3D> result(histologySliceNumberToCoordinate(sliceNumber));
    if (result.isOk()) {
        m_histologyEndSliceCoordinateLabel->setText(result.getValue().toString());
    }
    else {
        m_histologyEndSliceCoordinateLabel->setText("Invalid");
    }

    m_histologyEndSliceNumberSpinBox->setValue(sliceNumber);
    m_histologyEndSliceNameComboBox->setCurrentIndex(sliceNumber - 1);
    
    updateMontageOutputWidget();
}

/**
 * Called when histology start slice name is changed
 * @param index
 *    Index of name selected
 */
void
VolumeMontageSetupDialog::histologyStartSliceNameComboBoxActivated(int index)
{
    histologyStartSliceNumberSpinBoxValueChanged(index + 1);
}

/**
 * Called when histology end slice name is changed
 * @param index
 *    Index of name selected
 */
void
VolumeMontageSetupDialog::histologyEndSliceNameComboBoxActivated(int index)
{
    histologyEndSliceNumberSpinBoxValueChanged(index + 1);
}

/**
 * Convert a histology slice number to a coordinate
 * @param sliceNumber
 *   The slice number
 * @return
 *   The slice coordinate center
 */
FunctionResultValue<Vector3D>
VolumeMontageSetupDialog::histologySliceNumberToCoordinate(const int32_t sliceNumber) const
{
    Vector3D xyz;
    bool validFlag(false);
    CaretDataFile* cdf(m_histologyFileSelectionComboBox->getSelectedFile());
    if (cdf != NULL) {
        HistologySlicesFile* hsi(dynamic_cast<HistologySlicesFile*>(cdf));
        if (hsi != NULL) {
            const HistologySlice* slice(hsi->getHistologySliceByIndex(sliceNumber - 1));
            if (slice != NULL) {
                const BoundingBox boundingBox(slice->getStereotaxicXyzBoundingBox());
                if (boundingBox.isValid()) {
                    boundingBox.getCenter(xyz);
                    validFlag = true;
                }
            }
        }
    }
    
    return FunctionResultValue<Vector3D>(xyz, "", validFlag);
}

/**
 * @return Normal vector formed by histology slices
 */
FunctionResultValue<Vector3D>
VolumeMontageSetupDialog::getHistologySlicesNormalVector() const
{
    FunctionResultValue<Vector3D> resultStart(histologySliceNumberToCoordinate(m_histologyStartSliceNumberSpinBox->value()));
    FunctionResultValue<Vector3D> resultEnd(histologySliceNumberToCoordinate(m_histologyEndSliceNumberSpinBox->value()));
    Vector3D normalVector(0.0, 0.0, 1.0);
    AString msg;
    if (resultStart.isOk()
        && resultEnd.isOk()) {
        normalVector = (resultEnd.getValue() - resultStart.getValue()).normal();
    }
    else {
        msg = "Histology slices normal vector is invalid (default to (0, 0, 1))";
    }
    return FunctionResultValue<Vector3D>(normalVector,
                                         msg,
                                         msg.isEmpty());
}

/**
 * @return Slice view plane that best matches the histology slices normal vector
 */
FunctionResultValue<std::pair<VolumeSliceViewPlaneEnum::Enum,bool>>
VolumeMontageSetupDialog::histologyOrientationToVolumeSliceViewPlane() const
{
    bool flipFlag(false);
    VolumeSliceViewPlaneEnum::Enum sliceViewPlane(VolumeSliceViewPlaneEnum::AXIAL);
    const FunctionResultValue<Vector3D> normalVectorResult(getHistologySlicesNormalVector());
    if (normalVectorResult.isOk()) {
        const Vector3D normalVector(normalVectorResult.getValue());
        const float nx(std::fabs(normalVector[0]));
        const float ny(std::fabs(normalVector[1]));
        const float nz(std::fabs(normalVector[2]));
        if ((nx >= ny)
            && (nx >= nz)) {
            sliceViewPlane = VolumeSliceViewPlaneEnum::PARASAGITTAL;
            flipFlag = ((nx * normalVector[0]) < 0.0);
        }
        else if ((ny >= nx)
                 && (ny >= nz)) {
            sliceViewPlane = VolumeSliceViewPlaneEnum::CORONAL;
            flipFlag = ((ny * normalVector[1]) < 0.0);
        }
        else {
            sliceViewPlane = VolumeSliceViewPlaneEnum::AXIAL;
            flipFlag = ((nz * normalVector[2]) < 0.0);
        }
    }
    return FunctionResultValue<std::pair<VolumeSliceViewPlaneEnum::Enum,bool>>(std::make_pair(sliceViewPlane, flipFlag),
                                                                               normalVectorResult.getErrorMessage(),
                                                                               normalVectorResult.isOk());
}


/**
 * Called when volume file changed
 * @param caretDataFile
 *    File selected by user
 */
void
VolumeMontageSetupDialog::volumeFileSelected(CaretDataFile* caretDataFile)
{
    int32_t minSlice(0);
    int32_t maxSlice(-1);
    bool validFlag(false);
    if (caretDataFile != NULL) {
        VolumeMappableInterface* vmi(dynamic_cast<VolumeMappableInterface*>(caretDataFile));
        if (vmi != NULL) {
            int64_t dimI, dimJ, dimK, dimTime, dimCompontents;
            vmi->getDimensions(dimI, dimJ, dimK, dimTime, dimCompontents);
            
            switch (m_underlaySliceViewPlane) {
                case VolumeSliceViewPlaneEnum::ALL:
                    minSlice = 0;
                    maxSlice = std::max(dimI, std::max(dimJ, dimK));
                    break;
                case VolumeSliceViewPlaneEnum::AXIAL:
                    minSlice = 0;
                    maxSlice = dimK - 1;
                    break;
                case VolumeSliceViewPlaneEnum::CORONAL:
                    minSlice = 0;
                    maxSlice = dimJ - 1;
                    break;
                case VolumeSliceViewPlaneEnum::PARASAGITTAL:
                    minSlice = 0;
                    maxSlice = dimI - 1;
                    break;
            }
            
            QSignalBlocker startBlocker(m_volumeStartSliceIndexSpinBox);
            m_volumeStartSliceIndexSpinBox->setRange(minSlice, maxSlice);
            m_volumeStartSliceIndexSpinBox->setValue(0);
            QSignalBlocker endBlocker(m_volumeEndSliceIndexSpinBox);
            m_volumeEndSliceIndexSpinBox->setRange(minSlice, maxSlice);
            m_volumeEndSliceIndexSpinBox->setValue(maxSlice);
            updateVolumeSliceCoordinates();

            m_montageOutputParagittalSliceIndexSpinBox->setRange(0, dimI - 1);
            m_montageOutputCoronalSliceIndexSpinBox->setRange(0, dimJ - 1);
            m_montageOutputAxialSliceIndexSpinBox->setRange(0, dimK - 1);

            BoundingBox bb;
            vmi->getVoxelSpaceBoundingBox(bb);
            if (bb.isValid()) {
                m_montageOutputParagittalSliceCoordinateSpinBox->setRange(bb.getMinX(), bb.getMaxX());
                m_montageOutputCoronalSliceCoordinateSpinBox->setRange(bb.getMinY(), bb.getMaxY());
                m_montageOutputAxialSliceCoordinateSpinBox->setRange(bb.getMinZ(), bb.getMaxZ());
            }
            validFlag = true;
        }
    }
    
    m_volumeStartSliceIndexSpinBox->setEnabled(validFlag);
    m_volumeEndSliceIndexSpinBox->setEnabled(validFlag);

    updateMontageOutputWidget();
}

/**
 * Called when value changed
 * @param value
 *    New value
 */
void
VolumeMontageSetupDialog::volumeStartSliceIndexSpinBoxValueChanged(int /*value*/)
{
    updateVolumeSliceCoordinates();
    updateMontageOutputWidget();
}

/**
 * Called when value changed
 * @param value
 *    New value
 */
void
VolumeMontageSetupDialog::volumeEndSliceIndexSpinBoxValueChanged(int /*value*/)
{
    updateVolumeSliceCoordinates();
    updateMontageOutputWidget();
}

/**
 * Update the volume slice coordinates
 */
void
VolumeMontageSetupDialog::updateVolumeSliceCoordinates()
{
    FunctionResultValue<Vector3D> resultStart(volumeSliceIndexToCoordinate(m_volumeStartSliceIndexSpinBox->value()));
    if (resultStart.isOk()) {
        m_volumeStartSliceCoordinateLabel->setText(resultStart.getValue().toString());
    }
    else {
        m_volumeStartSliceCoordinateLabel->setText("Invalid");
    }

    FunctionResultValue<Vector3D> resultEnd(volumeSliceIndexToCoordinate(m_volumeEndSliceIndexSpinBox->value()));
    if (resultEnd.isOk()) {
        m_volumeEndSliceCoordinateLabel->setText(resultEnd.getValue().toString());
    }
    else {
        m_volumeEndSliceCoordinateLabel->setText("Invalid");
    }
}

/**
 * Convert a volume slice index to a coordinate for the currently selected axis
 * @param sliceIndex
 *   The slice index
 * @return
 *   The slice coordinate
 */
FunctionResultValue<Vector3D>
VolumeMontageSetupDialog::volumeSliceIndexToCoordinate(const int32_t sliceIndex) const
{
    Vector3D xyz;
    bool validFlag(false);
    
    CaretDataFile* cdf(m_volumeFileSelectionComboBox->getSelectedFile());
    if (cdf != NULL) {
        VolumeMappableInterface* vmi(dynamic_cast<VolumeMappableInterface*>(cdf));
        if (vmi != NULL) {
            int64_t dimI, dimJ, dimK, dimTime, dimCompontents;
            vmi->getDimensions(dimI, dimJ, dimK, dimTime, dimCompontents);
            const int64_t middleI((dimI > 1) ? (dimI / 2) : dimI);
            const int64_t middleJ((dimJ > 1) ? (dimJ / 2) : dimJ);
            const int64_t middleK((dimK > 1) ? (dimK / 2) : dimK);

            float x(0.0), y(0.0), z(0.0);
            switch (m_underlaySliceViewPlane) {
                case VolumeSliceViewPlaneEnum::ALL:
                    break;
                case VolumeSliceViewPlaneEnum::AXIAL:
                    vmi->indexToSpace(middleI, middleJ, sliceIndex, x, y, z);
                    break;
                case VolumeSliceViewPlaneEnum::CORONAL:
                    vmi->indexToSpace(middleI, sliceIndex, middleK, x, y, z);
                    break;
                case VolumeSliceViewPlaneEnum::PARASAGITTAL:
                    vmi->indexToSpace(sliceIndex, middleJ, middleK, x, y, z);
                    break;
            }
            xyz.set(x, y, z);
            validFlag = true;
        }
    }
    
    return FunctionResultValue<Vector3D>(xyz, "", validFlag);
}

/**
 * Convert a volume slice index to a coordinate for the currently selected axis
 * @param sliceIndex
 *   The slice index
 * @return
 *   The slice coordinate
 */
FunctionResultValue<int32_t>
VolumeMontageSetupDialog::volumeCoordinateToSliceIndex(const Vector3D& xyz) const
{
    int32_t sliceIndex(0);
    bool validFlag(false);
    
    CaretDataFile* cdf(m_volumeFileSelectionComboBox->getSelectedFile());
    if (cdf != NULL) {
        VolumeMappableInterface* vmi(dynamic_cast<VolumeMappableInterface*>(cdf));
        if (vmi != NULL) {
            int64_t ijk[3] { 0, 0, 0 };
            vmi->enclosingVoxel(xyz, ijk);
            
            switch (m_underlaySliceViewPlane) {
                case VolumeSliceViewPlaneEnum::ALL:
                    break;
                case VolumeSliceViewPlaneEnum::AXIAL:
                    sliceIndex = ijk[2];
                    break;
                case VolumeSliceViewPlaneEnum::CORONAL:
                    sliceIndex = ijk[1];
                    break;
                case VolumeSliceViewPlaneEnum::PARASAGITTAL:
                    sliceIndex = ijk[0];
                    break;
            }
            validFlag = true;
        }
    }
    
    return FunctionResultValue<int32_t>(sliceIndex, "", validFlag);
}

/**
 * Called when align to histology file axis checkbox is clicked
 * @param checked
 *   New checked status
 */
void
VolumeMontageSetupDialog::histologyAlignToHistologyFileAxisCheckBoxClicked(bool /*checked*/)
{
    updateMontageOutputWidget();
}

/**
 * Update content of montage output widget
 */
void
VolumeMontageSetupDialog::updateMontageOutputWidget()
{
    if (m_dialogCreationInProgressFlag) {
        return;
    }
    
    float indexI(0.0);
    float indexJ(0.0);
    float indexK(0.0);
    Vector3D stereoXYZ(0.0, 0.0, 0.0);
    float distanceBetweenEndAndStartSlicesMM(0.0);
    float distanceBetweenConsecutiveMontageSlicesMM(0.0);
    float numberOfSlicesPerStep(0.0);
    Vector3D rotationAngles(0.0, 0.0, 0.0);
    AString sliceViewPlaneName;
    
    bool histologyFlag(false);
    bool volumeFlag(false);
    const int32_t setUsingIndex(m_montageExtentFileTypeComboBox->currentIndex());
    if (setUsingIndex == m_montageExtentTypeHistologyFileIndex) {
        histologyFlag = true;
    }
    else if (setUsingIndex == m_montageExtentTypeVolumeFileIndex) {
        volumeFlag = true;
    }
    else {
        CaretAssert(0);
    }
    
    FunctionResultValue<Vector3D> resultStartCoord(Vector3D(), "", false);
    FunctionResultValue<Vector3D> resultEndCoord(Vector3D(), "", false);
    
    VolumeSliceViewPlaneEnum::Enum outputSlicePlane(m_underlaySliceViewPlane);
    
    if (histologyFlag) {
            resultStartCoord = histologySliceNumberToCoordinate(m_histologyStartSliceNumberSpinBox->value());
            resultEndCoord   = histologySliceNumberToCoordinate(m_histologyEndSliceNumberSpinBox->value());
            if (resultStartCoord.isOk()
                && resultEndCoord.isOk()) {
            }
    }
    else if (volumeFlag) {
        const int32_t startSliceIndex(m_volumeStartSliceIndexSpinBox->value());
        const int32_t endSliceIndex(m_volumeEndSliceIndexSpinBox->value());
        
        resultStartCoord = volumeSliceIndexToCoordinate(startSliceIndex);
        resultEndCoord   = volumeSliceIndexToCoordinate(endSliceIndex);
    }
    
    if (resultStartCoord.isOk()
        && resultEndCoord.isOk()) {
        const Vector3D startCoord(resultStartCoord.getValue());
        const Vector3D endCoord(resultEndCoord.getValue());
        Vector3D middleXYZ((endCoord
                            + startCoord)
                           / 2.0);
        CaretDataFile* cdf(m_volumeFileSelectionComboBox->getSelectedFile());
        if (cdf != NULL) {
            VolumeMappableInterface* vmi(dynamic_cast<VolumeMappableInterface*>(cdf));
            if (vmi != NULL) {
                distanceBetweenEndAndStartSlicesMM = (endCoord - startCoord).length();
                const float numMontageSlices(m_montageInputRowsSpinBox->value()
                                             * m_montageInputColumnsSpinBox->value());
                if (numMontageSlices > 1.0) {
                    distanceBetweenConsecutiveMontageSlicesMM = distanceBetweenEndAndStartSlicesMM / (numMontageSlices - 1);
                }
                
                float ijk[3] { 0.0, 0.0, 0.0 };
                m_underlayVolumeFile->spaceToIndex(middleXYZ[0], middleXYZ[1], middleXYZ[2],
                                                   ijk[0], ijk[1], ijk[2]);
                indexI = std::round(ijk[0]);
                indexJ = std::round(ijk[1]);
                indexK = std::round(ijk[2]);
                m_underlayVolumeFile->indexToSpace(indexI, indexJ, indexK,
                                                   middleXYZ[0], middleXYZ[1], middleXYZ[2]);
                stereoXYZ = middleXYZ;

                int64_t sliceZero[3] { 0, 0, 0 };
                int64_t sliceOne[3] { 1, 1, 1 };
                Vector3D xyzZero;
                Vector3D xyzOne;
                vmi->indexToSpace(sliceZero, xyzZero);
                vmi->indexToSpace(sliceOne,  xyzOne);
                
                /*
                 * Align to histology file axis?
                 */
                if (histologyFlag
                    && m_histologyAlignToFileAxisCheckBox->isChecked()) {
                    FunctionResultValue<std::pair<VolumeSliceViewPlaneEnum::Enum,bool>> slicePlaneResult(histologyOrientationToVolumeSliceViewPlane());
                    bool flipFlag(false);
                    if (slicePlaneResult.isOk()) {
                        outputSlicePlane = slicePlaneResult.getValue().first;
                        flipFlag   = slicePlaneResult.getValue().second;
                    }
                    const Vector3D histologyVector((endCoord - startCoord).normal());
                    
                    Vector3D sliceVector(0.0, 0.0, 1.0);
                    switch (outputSlicePlane) {
                        case VolumeSliceViewPlaneEnum::ALL:
                            break;
                        case VolumeSliceViewPlaneEnum::AXIAL:
                            sliceVector.set(0.0, 0.0, -1.0);
                            break;
                        case VolumeSliceViewPlaneEnum::CORONAL:
                            sliceVector.set(0.0, 1.0, 0.0);
                            break;
                        case VolumeSliceViewPlaneEnum::PARASAGITTAL:
                            sliceVector.set(1.0, 0.0, 0.0);
                            break;
                    }
                    if (flipFlag) {
                        sliceVector = -sliceVector;
                    }
                    
                    const QVector3D hv(histologyVector[0],
                                       histologyVector[1],
                                       histologyVector[2]);
                    const QVector3D sv(sliceVector[0],
                                       sliceVector[1],
                                       sliceVector[2]);
                    const QQuaternion q(QQuaternion::rotationTo(sv, hv));
                    QVector3D eulerAngles(q.toEulerAngles());
                    rotationAngles.set(eulerAngles[0],
                                       eulerAngles[1],
                                       -eulerAngles[2]); /* look down Z-axis (positive to negative) */
                }
                else {
                    outputSlicePlane = m_underlaySliceViewPlane;
                    rotationAngles.set(0.0, 0.0, 0.0);
                    
                }
                
                float thicknessOfOneSliceMM(0.0);
                switch (outputSlicePlane) {
                    case VolumeSliceViewPlaneEnum::ALL:
                        break;
                    case VolumeSliceViewPlaneEnum::AXIAL:
                        sliceViewPlaneName = "Axial";
                        thicknessOfOneSliceMM = std::fabs(xyzOne[2] - xyzZero[2]);
                        break;
                    case VolumeSliceViewPlaneEnum::CORONAL:
                        sliceViewPlaneName = "Coronal";
                        thicknessOfOneSliceMM = std::fabs(xyzOne[1] - xyzZero[1]);
                        break;
                    case VolumeSliceViewPlaneEnum::PARASAGITTAL:
                        sliceViewPlaneName = "Parasagittal";
                        thicknessOfOneSliceMM = std::fabs(xyzOne[0] - xyzZero[0]);
                        break;
                }
                
                if (thicknessOfOneSliceMM != 0.0) {
                    numberOfSlicesPerStep = (distanceBetweenConsecutiveMontageSlicesMM
                                             / thicknessOfOneSliceMM);
                }
            }
        }
    }
    
    QSignalBlocker paraIndexBlocker(m_montageOutputParagittalSliceIndexSpinBox);
    m_montageOutputParagittalSliceIndexSpinBox->setValue(indexI);
    QSignalBlocker coronalIndexBlocker(m_montageOutputCoronalSliceIndexSpinBox);
    m_montageOutputCoronalSliceIndexSpinBox->setValue(indexJ);
    QSignalBlocker axialIndexBlocker(m_montageOutputAxialSliceIndexSpinBox);
    m_montageOutputAxialSliceIndexSpinBox->setValue(indexK);
    
    QSignalBlocker paraCoordBlocker(m_montageOutputParagittalSliceCoordinateSpinBox);
    m_montageOutputParagittalSliceCoordinateSpinBox->setValue(stereoXYZ[0]);
    QSignalBlocker coronalCoordBlocker(m_montageOutputCoronalSliceCoordinateSpinBox);
    m_montageOutputCoronalSliceCoordinateSpinBox->setValue(stereoXYZ[1]);
    QSignalBlocker axialCoordBlocker(m_montageOutputAxialSliceCoordinateSpinBox);
    m_montageOutputAxialSliceCoordinateSpinBox->setValue(stereoXYZ[2]);
    
    m_montageOutputRangeLabel->setText(QString::number(distanceBetweenEndAndStartSlicesMM, 'f', 2) + " mm");
    m_montageOutputSliceStepLabel->setText(QString::number(numberOfSlicesPerStep, 'f', 2) + " slices");
    m_montageOutputStepDistanceLabel->setText(QString::number(distanceBetweenConsecutiveMontageSlicesMM, 'f', 3) + " mm");
    
    m_montageOutputRotationAnglesLabel->setText(rotationAngles.toString());
    m_montageOutputSliceViewPlaneLabel->setText(sliceViewPlaneName);
    
    m_outputSlicePlane = outputSlicePlane;
    m_outputParasagittalSliceCoordinate = m_montageOutputParagittalSliceCoordinateSpinBox->value();
    m_outputCoronalSliceCoordinate = m_montageOutputCoronalSliceCoordinateSpinBox->value();
    m_outputAxialSliceCoordinate = m_montageOutputAxialSliceCoordinateSpinBox->value();
    m_outputMontageStep = numberOfSlicesPerStep;
    m_outputMontageRows = m_montageInputRowsSpinBox->value();
    m_outputMontageColumns = m_montageInputColumnsSpinBox->value();
    m_outputMprRotationAngles = rotationAngles;
}

/**
 * Called when the montage extent file type combo box is activated
 * @param index
 *    Index of item selected
 */
void
VolumeMontageSetupDialog::montageExtentFileTypeComboBoxActivated(int index)
{
    if (index == m_montageExtentTypeHistologyFileIndex) {
        m_volumeSliceRangeSourceLayout->setCurrentWidget(m_montageExtentHistologyFileWidget);
    }
    else if (index == m_montageExtentTypeVolumeFileIndex) {
        m_volumeSliceRangeSourceLayout->setCurrentWidget(m_montageExtentVolumeFileWidget);
    }
    else {
        CaretAssertMessage(0, "Invalid index for source index");
    }
    
    updateMontageOutputWidget();
}

/**
 * Apply the montage settings.
 * @return True if the settings were applied successfully.
 */
bool
VolumeMontageSetupDialog::applyMontageSettings()
{
    switch (m_outputSlicePlane) {
        case VolumeSliceViewPlaneEnum::ALL:
            break;
        case VolumeSliceViewPlaneEnum::AXIAL:
            m_browserTabContent->setShowVolumeViewAxialSlice(true);
            break;
        case VolumeSliceViewPlaneEnum::CORONAL:
            m_browserTabContent->setShowVolumeViewCoronalSlice(true);
            break;
        case VolumeSliceViewPlaneEnum::PARASAGITTAL:
            m_browserTabContent->setShowVolumeViewParasagittalSlice(true);
            break;
    }
    m_browserTabContent->setVolumeSliceCoordinateParasagittal(m_outputParasagittalSliceCoordinate);
    m_browserTabContent->setVolumeSliceCoordinateCoronal(m_outputCoronalSliceCoordinate);
    m_browserTabContent->setVolumeSliceCoordinateAxial(m_outputAxialSliceCoordinate);
    m_browserTabContent->setVolumeMontageNumberOfRows(m_outputMontageRows);
    m_browserTabContent->setVolumeMontageNumberOfColumns(m_outputMontageColumns);
    m_browserTabContent->setVolumeMontageSliceSpacing(m_outputMontageStep);
    m_browserTabContent->setMprThreeRotationAngles(m_outputMprRotationAngles);
    
    EventManager::get()->sendEvent(EventGraphicsPaintSoonAllWindows().getPointer());
    EventManager::get()->sendEvent(EventUserInterfaceUpdate().getPointer());

    return true;
}

/**
 * Called when the ok button is clicked
 */
void
VolumeMontageSetupDialog::okButtonClicked()
{
    if (applyMontageSettings()) {
        WuQDialogModal::okButtonClicked();
    }
}

/**
 * Called when the apply button is clicked
 * @param userPushButton
 *   Button that was clicked
 * @return Result to close or keep dialog open.
 */
VolumeMontageSetupDialog::DialogUserButtonResult
VolumeMontageSetupDialog::userButtonPressed(QPushButton* userPushButton)
{
    if (userPushButton == m_applyPushButton) {
        applyMontageSettings();
    }
    else {
        CaretAssert(0);
    }
    return DialogUserButtonResult::RESULT_NONE;
}

